three-slicer 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,9 @@
1
- // 슬라이서 워커 생성 — 이 파일은 번들되지 않고 dist/ 에 원형 복사된다 (build 스크립트).
2
- // 이유: 소비자 번들러(Vite/webpack)가 워커를 청크로 인식하려면 `new Worker(new URL('리터럴', import.meta.url))`
3
- // 정적 패턴이 소비자에게 보이는 파일에 그대로 남아 있어야 한다. viewer 자체 lib 빌드가 이걸 처리하면
4
- // 사이트 루트 기준 절대경로 자산으로 굳어져 소비자 앱에서 404 가 난다.
5
- // 경로 '../../engine/…' 은 dist/ 기준: 모노레포(packages/viewer/dist→packages/engine)와
6
- // npm 설치(@three-slicer/ 스코프 형제 디렉토리) 양쪽에서 engine 패키지로 해석된다.
1
+ // Slicer worker factory — this file is not bundled; the build script copies it verbatim into dist/.
2
+ // Why: for consumer bundlers (Vite/webpack) to recognize the worker as a chunk, the static
3
+ // `new Worker(new URL('literal', import.meta.url))` pattern must survive in a file the consumer sees. If the viewer's own
4
+ // lib build handled it, the worker would be frozen into a site-root-absolute asset path and 404 in consumer apps.
5
+ // The '../../engine/…' path is relative to dist/: it resolves to the engine package both in the monorepo
6
+ // (packages/viewer/dist -> packages/engine) and in an npm install (sibling directory under the @three-slicer/ scope).
7
7
  export function makeSlicerWorker() {
8
8
  return new Worker(new URL('../../engine/src/slicer.worker.js', import.meta.url), { type: 'module' })
9
9
  }
@@ -1,10 +1,10 @@
1
- import * as C from "three";
2
- import { OBJLoader as U } from "three/examples/jsm/loaders/OBJLoader.js";
3
- import { PLYLoader as V } from "three/examples/jsm/loaders/PLYLoader.js";
4
- import { AMFLoader as W } from "three/examples/jsm/loaders/AMFLoader.js";
5
- import { unzipSync as X } from "three/examples/jsm/libs/fflate.module.js";
1
+ import * as B from "three";
2
+ import { OBJLoader as C } from "three/examples/jsm/loaders/OBJLoader.js";
3
+ import { PLYLoader as N } from "three/examples/jsm/loaders/PLYLoader.js";
4
+ import { AMFLoader as V } from "three/examples/jsm/loaders/AMFLoader.js";
5
+ import { unzipSync as W } from "three/examples/jsm/libs/fflate.module.js";
6
6
  const x = [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0];
7
- function J(t, e) {
7
+ function X(t, e) {
8
8
  const s = new Array(12);
9
9
  for (let n = 0; n < 4; n++)
10
10
  for (let o = 0; o < 3; o++)
@@ -22,7 +22,7 @@ function w(t, e) {
22
22
  return n ? n[1] : null;
23
23
  }
24
24
  const z = /<vertex\s+x="([^"]*)"\s+y="([^"]*)"\s+z="([^"]*)"/g, I = /<triangle\s+v1="([^"]*)"\s+v2="([^"]*)"\s+v3="([^"]*)"/g;
25
- function Y(t) {
25
+ function J(t) {
26
26
  const e = [];
27
27
  z.lastIndex = 0;
28
28
  let s;
@@ -36,7 +36,7 @@ function Y(t) {
36
36
  for (const o of t.match(/<triangle\b[^>]*>/g) || []) n.push(+w(o, "v1"), +w(o, "v2"), +w(o, "v3"));
37
37
  return n.length ? { verts: e, tris: n } : null;
38
38
  }
39
- function H(t) {
39
+ function Y(t) {
40
40
  const e = /* @__PURE__ */ new Map(), s = /<object\b([^>]*)>([\s\S]*?)<\/object>/g;
41
41
  let n;
42
42
  for (; n = s.exec(t); ) {
@@ -47,7 +47,7 @@ function H(t) {
47
47
  const h = w(d, "objectid");
48
48
  h && p.push({ objectid: h, path: w(d, "p:path") || w(d, "path"), transform: R(w(d, "transform")) });
49
49
  }
50
- e.set(i, p.length ? { components: p } : { mesh: Y(c) });
50
+ e.set(i, p.length ? { components: p } : { mesh: J(c) });
51
51
  }
52
52
  const o = [], u = /<build\b[^>]*>([\s\S]*?)<\/build>/.exec(t);
53
53
  if (u)
@@ -61,13 +61,13 @@ function L(t) {
61
61
  const e = String(t).replace(/^\/+/, "");
62
62
  return e.includes("%") ? decodeURIComponent(e) : e;
63
63
  }
64
- function Q(t, e = "model") {
65
- const s = ArrayBuffer.isView(t) ? new Uint8Array(t.buffer, t.byteOffset, t.byteLength) : new Uint8Array(t), n = X(s), o = /* @__PURE__ */ new Map();
64
+ function H(t, e = "model") {
65
+ const s = ArrayBuffer.isView(t) ? new Uint8Array(t.buffer, t.byteOffset, t.byteLength) : new Uint8Array(t), n = W(s), o = /* @__PURE__ */ new Map();
66
66
  for (const a of Object.keys(n)) o.set(L(a), n[a]);
67
67
  const u = new TextDecoder(), i = /* @__PURE__ */ new Map(), c = (a) => {
68
68
  const m = L(a);
69
69
  if (i.has(m)) return i.get(m);
70
- const l = o.get(m), M = l ? H(u.decode(l)) : null;
70
+ const l = o.get(m), M = l ? Y(u.decode(l)) : null;
71
71
  return i.set(m, M), M;
72
72
  };
73
73
  let p = "3D/3dmodel.model";
@@ -80,13 +80,13 @@ function Q(t, e = "model") {
80
80
  }
81
81
  }
82
82
  const h = c(p);
83
- if (!h) throw new Error(`3MF 루트 모델 없음: ${p}`);
83
+ if (!h) throw new Error(`3MF root model not found: ${p}`);
84
84
  const r = [], f = (a, m, l, M, $) => {
85
85
  if ($ > 16) return;
86
86
  const T = c(m), E = T == null ? void 0 : T.objects.get(a);
87
87
  if (!E) return;
88
88
  if (E.components) {
89
- for (const y of E.components) f(y.objectid, y.path || m, J(y.transform, l), M, $ + 1);
89
+ for (const y of E.components) f(y.objectid, y.path || m, X(y.transform, l), M, $ + 1);
90
90
  return;
91
91
  }
92
92
  if (!E.mesh) return;
@@ -105,16 +105,16 @@ function Q(t, e = "model") {
105
105
  f(a.objectid, a.path || p, a.transform, l, 0), l.length >= 9 && r.push({ name: g.length > 1 ? `${e}#${m + 1}` : e, tris: new Float32Array(l) });
106
106
  }), r;
107
107
  }
108
- const P = ["stl", "obj", "3mf", "amf", "ply"], _ = /* @__PURE__ */ new Map();
108
+ const P = ["stl", "obj", "3mf", "amf", "ply"], U = /* @__PURE__ */ new Map();
109
109
  function et(t, e) {
110
110
  for (const s of (Array.isArray(t) ? t : String(t).split(",")).map((n) => n.trim().toLowerCase()))
111
- _.set(s, e), P.includes(s) || P.push(s);
111
+ U.set(s, e), P.includes(s) || P.push(s);
112
112
  }
113
- function q(t) {
113
+ function Q(t) {
114
114
  const e = t.lastIndexOf(".");
115
115
  return e < 0 ? "" : t.slice(e + 1).toLowerCase();
116
116
  }
117
- function G(t) {
117
+ function q(t) {
118
118
  const e = new DataView(t);
119
119
  if (t.byteLength >= 84) {
120
120
  const i = e.getUint32(80, !0);
@@ -135,11 +135,11 @@ function G(t) {
135
135
  for (; u = n.exec(s); ) o.push(+u[1], +u[2], +u[3]);
136
136
  return o.length < 9 ? null : new Float32Array(o);
137
137
  }
138
- function B(t, e) {
138
+ function _(t, e) {
139
139
  var d;
140
140
  const s = (d = t == null ? void 0 : t.attributes) == null ? void 0 : d.position;
141
141
  if (!s || s.count < 3) return null;
142
- const n = t.index, o = new C.Vector3(), u = Math.floor((n ? n.count : s.count) / 3), i = new Float32Array(u * 9);
142
+ const n = t.index, o = new B.Vector3(), u = Math.floor((n ? n.count : s.count) / 3), i = new Float32Array(u * 9);
143
143
  let c = 0;
144
144
  const p = (h) => {
145
145
  o.fromBufferAttribute(s, h), e && o.applyMatrix4(e), i[c++] = o.x, i[c++] = o.y, i[c++] = o.z;
@@ -158,7 +158,7 @@ function D(t) {
158
158
  }), e;
159
159
  }
160
160
  function O(t, e, s) {
161
- const n = e.map((c) => B(c.geometry, c.matrix)).filter(Boolean);
161
+ const n = e.map((c) => _(c.geometry, c.matrix)).filter(Boolean);
162
162
  if (!n.length) return [];
163
163
  if (s && n.length > 1)
164
164
  return n.map((c, p) => ({ name: `${t}#${p + 1}`, modelPos: c }));
@@ -172,37 +172,37 @@ function O(t, e, s) {
172
172
  return [{ name: t, modelPos: u }];
173
173
  }
174
174
  async function nt(t, e) {
175
- const s = q(t);
175
+ const s = Q(t);
176
176
  switch (s) {
177
177
  case "stl": {
178
- const n = G(e);
179
- if (!n) throw new Error("STL 파싱 실패");
178
+ const n = q(e);
179
+ if (!n) throw new Error("Failed to parse STL");
180
180
  return [{ name: t, modelPos: n }];
181
181
  }
182
182
  case "obj": {
183
- const n = new U().parse(new TextDecoder().decode(e));
183
+ const n = new C().parse(new TextDecoder().decode(e));
184
184
  return O(t, D(n), !1);
185
185
  }
186
186
  case "ply": {
187
- const n = new V().parse(e), o = B(n, null);
188
- if (!o) throw new Error("PLY 지오메트리 없음");
187
+ const n = new N().parse(e), o = _(n, null);
188
+ if (!o) throw new Error("No PLY geometry");
189
189
  return [{ name: t, modelPos: o }];
190
190
  }
191
191
  case "3mf": {
192
- const n = Q(e, t).map((o) => ({ name: o.name, modelPos: o.tris }));
193
- if (!n.length) throw new Error("3MF 메시 없음");
192
+ const n = H(e, t).map((o) => ({ name: o.name, modelPos: o.tris }));
193
+ if (!n.length) throw new Error("No mesh in 3MF");
194
194
  return n;
195
195
  }
196
196
  case "amf": {
197
- const n = new W().parse(e), o = O(t, D(n), !0);
198
- if (!o.length) throw new Error("AMF 메시 없음");
197
+ const n = new V().parse(e), o = O(t, D(n), !0);
198
+ if (!o.length) throw new Error("No mesh in AMF");
199
199
  return o;
200
200
  }
201
201
  default: {
202
- const n = _.get(s);
203
- if (!n) throw new Error(`지원하지 않는 포맷: .${s}`);
202
+ const n = U.get(s);
203
+ if (!n) throw new Error(`Unsupported format: .${s}`);
204
204
  const o = await n(e, t);
205
- if (!(o != null && o.length)) throw new Error(`.${s} 메시 없음`);
205
+ if (!(o != null && o.length)) throw new Error(`No mesh in .${s}`);
206
206
  return o;
207
207
  }
208
208
  }
@@ -249,7 +249,7 @@ function ot(t) {
249
249
  }
250
250
  export {
251
251
  P as SUPPORTED_EXT,
252
- q as fileExt,
252
+ Q as fileExt,
253
253
  nt as loadModel,
254
254
  et as registerLoader,
255
255
  ot as splitConnectedComponents
@@ -1,33 +1,4 @@
1
- const le = [
2
- 0,
3
- 1,
4
- 2,
5
- 0,
6
- 2,
7
- 3,
8
- // front spike
9
- 0,
10
- 3,
11
- 4,
12
- 0,
13
- 4,
14
- 5,
15
- // right/bottom body
16
- 0,
17
- 5,
18
- 6,
19
- 0,
20
- 6,
21
- 1,
22
- // left/top body
23
- 5,
24
- 4,
25
- 7,
26
- 5,
27
- 7,
28
- 6
29
- // back spike
30
- ], U = {
1
+ const U = {
31
2
  0: [0.42, 0.45, 0.5],
32
3
  1: [0.85, 0.51, 0.17],
33
4
  2: [0.21, 0.45, 0.76],
@@ -45,42 +16,61 @@ function ie(t) {
45
16
  const i = Math.round(t[0] * 255), s = Math.round(t[1] * 255), n = Math.round(t[2] * 255);
46
17
  return i << 16 | s << 8 | n;
47
18
  }
48
- function ue(t, i) {
19
+ const le = { 1: "Wall", 2: "Sparse", 3: "Solid", 4: "Skirt", 5: "Support", 6: "Raft", 7: "Gap fill", 8: "Thin wall", 9: "Bridge", 10: "Ironing", 11: "Prime" }, _e = [
20
+ [11, 44, 122],
21
+ [19, 89, 133],
22
+ [28, 136, 145],
23
+ [4, 214, 15],
24
+ [170, 242, 0],
25
+ [252, 249, 3],
26
+ [245, 206, 10],
27
+ [227, 136, 32],
28
+ [209, 104, 48],
29
+ [194, 82, 60],
30
+ [148, 38, 22]
31
+ ].map((t) => [t[0] / 255, t[1] / 255, t[2] / 255]);
32
+ function ce(t, i, s, n) {
33
+ const l = n.length;
34
+ if (!(s > i)) return n[0];
35
+ const a = (s - i) / (l - 1), h = (t - i) / a, _ = Math.max(0, Math.min(l - 1, Math.floor(h))), y = Math.max(0, Math.min(l - 1, _ + 1)), v = h - _, r = n[_], x = n[y];
36
+ return [r[0] + (x[0] - r[0]) * v, r[1] + (x[1] - r[1]) * v, r[2] + (x[2] - r[2]) * v];
37
+ }
38
+ function pe(t, i) {
49
39
  const s = t.length, n = i > 0 ? i : 0.42, l = new Array(s);
50
40
  for (let e = 0; e < s; e++) {
51
41
  const o = t[e].z;
52
42
  l[e] = Math.max(0.02, e === 0 ? o : o - t[e - 1].z);
53
43
  }
54
- const a = [], h = [], _ = [], y = [], v = [], r = [], x = [], b = [], A = [], M = [], L = new Float64Array(16), P = [], k = [];
44
+ const a = [], h = [], _ = [], y = [], v = [], r = [], x = [], b = [], A = [], M = [], L = new Float64Array(16), P = [], D = [];
55
45
  let W = -1, $ = 0, R = 0, H = 0, E = -1, c = 0;
56
- const d = 1e-4, u = (e, o, g, m, p, w) => (a.push(e), h.push(o), _.push(g), r.push(m), y.push(p), v.push(w), x.push(c), b.push(!1), a.length - 1);
46
+ const d = 1e-4, p = (e, o, g, m, u, w) => (a.push(e), h.push(o), _.push(g), r.push(m), y.push(u), v.push(w), x.push(c), b.push(!1), a.length - 1);
57
47
  for (let e = 0; e < s; e++) {
58
48
  const o = t[e].paths, g = t[e].widths, m = l[e];
59
49
  if (c = e, !!o)
60
- for (let p = 0; p < o.length; p += 8) {
61
- const w = o[p + 3], F = o[p], I = o[p + 1], G = o[p + 2], S = o[p + 4], V = o[p + 5], B = o[p + 6];
50
+ for (let u = 0; u < o.length; u += 8) {
51
+ const w = o[u + 3], F = o[u], S = o[u + 1], G = o[u + 2], I = o[u + 4], V = o[u + 5], B = o[u + 6];
62
52
  if (w === 0) {
63
- P.push(F, I, G, S, V, B), k.push(e);
53
+ P.push(F, S, G, I, V, B), D.push(e);
64
54
  continue;
65
55
  }
66
- const O = g && g[p / 8] > 0 ? g[p / 8] : n;
67
- w < 16 && (L[w] += Math.hypot(S - F, V - I));
68
- let D;
69
- W >= 0 && E === w && Math.abs($ - F) < d && Math.abs(R - I) < d && Math.abs(H - G) < d ? (D = W, u(S, V, B, w, m, O)) : (D = u(F, I, G, w, m, O), u(S, V, B, w, m, O)), b[D] = !0, W = D + 1, $ = S, R = V, H = B, E = w, A.push(D), M.push(e);
56
+ const O = g && g[u / 8] > 0 ? g[u / 8] : n;
57
+ w < 16 && (L[w] += Math.hypot(I - F, V - S));
58
+ let k;
59
+ W >= 0 && E === w && Math.abs($ - F) < d && Math.abs(R - S) < d && Math.abs(H - G) < d ? (k = W, p(I, V, B, w, m, O)) : (k = p(F, S, G, w, m, O), p(I, V, B, w, m, O)), b[k] = !0, W = k + 1, $ = I, R = V, H = B, E = w, A.push(k), M.push(e);
70
60
  }
71
61
  }
72
62
  const f = a.length, C = A.length, z = new Float32Array(f * 4), Y = new Float32Array(f * 4);
73
- let ee = 0, ne = !1, j = 1 / 0, T = 1 / 0, X = 1 / 0, Z = -1 / 0, q = -1 / 0, J = -1 / 0;
63
+ let ee = 0, ne = !1, T = 1 / 0, j = 1 / 0, X = 1 / 0, Z = -1 / 0, q = -1 / 0, J = -1 / 0;
74
64
  for (let e = 0; e < f; e++) {
75
- const o = y[e], g = a[e], m = h[e], p = _[e] - 0.5 * o;
76
- z[e * 4] = g, z[e * 4 + 1] = m, z[e * 4 + 2] = p;
65
+ const o = y[e], g = a[e], m = h[e], u = _[e] - 0.5 * o;
66
+ z[e * 4] = g, z[e * 4 + 1] = m, z[e * 4 + 2] = u;
77
67
  const w = e > 0 && b[e - 1], F = b[e];
78
- let I = 0;
68
+ let S = 0;
79
69
  if (w || F) {
80
- const G = w ? a[e] - a[e - 1] : 0, S = w ? h[e] - h[e - 1] : 0, V = w ? _[e] - _[e - 1] : 0, B = F ? a[e + 1] - a[e] : 0, O = F ? h[e + 1] - h[e] : 0, D = F ? _[e + 1] - _[e] : 0;
81
- I = Math.atan2(G * O - S * B, G * B + S * O + V * D);
70
+ const G = w ? a[e] - a[e - 1] : 0, I = w ? h[e] - h[e - 1] : 0, V = w ? _[e] - _[e - 1] : 0, B = F ? a[e + 1] - a[e] : 0, O = F ? h[e + 1] - h[e] : 0, k = F ? _[e + 1] - _[e] : 0;
71
+ S = Math.atan2(G * O - I * B, G * B + I * O + V * k);
82
72
  }
83
- Y[e * 4] = o, Y[e * 4 + 1] = v[e], Y[e * 4 + 2] = I, Y[e * 4 + 3] = ie(U[r[e]] || U[1]), (!Number.isFinite(g) || !Number.isFinite(m) || !Number.isFinite(p) || !Number.isFinite(I)) && (ne = !0), ee = Math.max(ee, Math.abs(g), Math.abs(m), Math.abs(p)), g < j && (j = g), g > Z && (Z = g), m < T && (T = m), m > q && (q = m), p < X && (X = p), p > J && (J = p);
73
+ Y[e * 4] = o, Y[e * 4 + 1] = v[e], Y[e * 4 + 2] = S, Y[e * 4 + 3] = ie(U[r[e]] || U[1]), (!Number.isFinite(g) || !Number.isFinite(m) || !Number.isFinite(u) || !Number.isFinite(S)) && (ne = !0), ee = Math.max(ee, Math.abs(g), Math.abs(m), Math.abs(u)), g < T && (T = g), g > Z && (Z = g), m < j && (j = m), m > q && (q = m), u < X && (X = u), u > J && (J = u);
84
74
  }
85
75
  const te = new Uint32Array(C * 4);
86
76
  for (let e = 0; e < C; e++)
@@ -96,24 +86,23 @@ function ue(t, i) {
96
86
  oe[o + 1] = e;
97
87
  }
98
88
  }
99
- const Q = k.length, N = new Float32Array(Q * 6);
89
+ const Q = D.length, N = new Float32Array(Q * 6);
100
90
  for (let e = 0; e < N.length; e++) N[e] = P[e];
101
91
  for (let e = 0; e < N.length; e += 3) {
102
92
  const o = N[e], g = N[e + 1], m = N[e + 2];
103
- o < j && (j = o), o > Z && (Z = o), g < T && (T = g), g > q && (q = g), m < X && (X = m), m > J && (J = m);
93
+ o < T && (T = o), o > Z && (Z = o), g < j && (j = g), g > q && (q = g), m < X && (X = m), m > J && (J = m);
104
94
  }
105
95
  const re = new Int32Array(s + 1);
106
96
  {
107
97
  let e = 0;
108
98
  for (let o = 0; o < s; o++) {
109
- for (; e < Q && k[e] === o; ) e++;
99
+ for (; e < Q && D[e] === o; ) e++;
110
100
  re[o + 1] = e;
111
101
  }
112
102
  }
113
- const se = f + Q > 0 ? { min: [j, T, X], max: [Z, q, J] } : null;
103
+ const se = f + Q > 0 ? { min: [T, j, X], max: [Z, q, J] } : null;
114
104
  return { position: z, hwa: Y, segIndex: te, nV: f, nSeg: C, layerSegPrefix: oe, travelPos: N, travelPrefix: re, nTrav: Q, layerCount: s, maxAbs: ee, hasNaN: ne, meta: K, typeLengths: L, bbox: se };
115
105
  }
116
- const _e = { 1: "벽", 2: "스파스", 3: "솔리드", 4: "스커트", 5: "서포트", 6: "래프트", 7: "갭필", 8: "씬월", 9: "브리지", 10: "아이어닝", 11: "프라임" };
117
106
  function ve(t) {
118
107
  let i = 0;
119
108
  for (let n = 1; n < 16; n++) i += t[n] || 0;
@@ -121,74 +110,11 @@ function ve(t) {
121
110
  if (i <= 0) return s;
122
111
  for (let n = 1; n < 16; n++) {
123
112
  const l = t[n] || 0;
124
- l > 0 && s.push({ type: n, label: _e[n] || "t" + n, pct: 100 * l / i, color: U[n] || U[1] });
113
+ l > 0 && s.push({ type: n, label: le[n] || "t" + n, pct: 100 * l / i, color: U[n] || U[1] });
125
114
  }
126
115
  return s.sort((n, l) => l.pct - n.pct);
127
116
  }
128
- const ce = [
129
- [11, 44, 122],
130
- [19, 89, 133],
131
- [28, 136, 145],
132
- [4, 214, 15],
133
- [170, 242, 0],
134
- [252, 249, 3],
135
- [245, 206, 10],
136
- [227, 136, 32],
137
- [209, 104, 48],
138
- [194, 82, 60],
139
- [148, 38, 22]
140
- ].map((t) => [t[0] / 255, t[1] / 255, t[2] / 255]);
141
- function he(t, i, s, n) {
142
- const l = n.length;
143
- if (!(s > i)) return n[0];
144
- const a = (s - i) / (l - 1), h = (t - i) / a, _ = Math.max(0, Math.min(l - 1, Math.floor(h))), y = Math.max(0, Math.min(l - 1, _ + 1)), v = h - _, r = n[_], x = n[y];
145
- return [r[0] + (x[0] - r[0]) * v, r[1] + (x[1] - r[1]) * v, r[2] + (x[2] - r[2]) * v];
146
- }
147
- const ae = [
148
- { key: "feature", label: "Feature type", cont: !1, unit: "" },
149
- { key: "speed", label: "Speed", cont: !0, unit: "mm/s" },
150
- { key: "height", label: "Layer Height", cont: !0, unit: "mm" },
151
- { key: "width", label: "Line Width", cont: !0, unit: "mm" },
152
- { key: "fan", label: "Fan Speed", cont: !0, unit: "%" },
153
- { key: "temp", label: "Temperature", cont: !0, unit: "°C" }
154
- ];
155
- function de(t, i, s, n) {
156
- const l = i.vType[s], a = i.vLayer[s], h = a === 0;
157
- switch (t) {
158
- case "height":
159
- return i.vHeight[s];
160
- case "width":
161
- return i.vWidth[s];
162
- case "speed":
163
- return h ? n.firstLayerSpeed : n.speedByType[l] ?? n.speedByType[1];
164
- case "fan":
165
- return a < n.closeFanLayers ? 0 : l === 9 ? 100 : n.fanNormal;
166
- case "temp":
167
- return h ? n.tempFirst : n.tempNormal;
168
- default:
169
- return 0;
170
- }
171
- }
172
- function ge(t, i, s) {
173
- const { meta: n, nV: l } = t, a = new Float32Array(l * 4), h = ae.find((r) => r.key === i) || ae[0];
174
- if (!h.cont) {
175
- for (let r = 0; r < l; r++) a[r * 4] = ie(U[n.vType[r]] || U[1]);
176
- return { color: a, min: 0, max: 0, viewType: i, label: h.label, unit: h.unit, cont: !1 };
177
- }
178
- let _ = 1 / 0, y = -1 / 0;
179
- const v = new Float32Array(l);
180
- for (let r = 0; r < l; r++) {
181
- const x = de(i, n, r, s);
182
- v[r] = x, x < _ && (_ = x), x > y && (y = x);
183
- }
184
- Number.isFinite(_) || (_ = 0, y = 1);
185
- for (let r = 0; r < l; r++) {
186
- const x = he(v[r], _, y, ce);
187
- a[r * 4] = ie(x);
188
- }
189
- return { color: a, min: _, max: y, viewType: i, label: h.label, unit: h.unit, cont: !0 };
190
- }
191
- const fe = `
117
+ const he = `
192
118
  precision highp float;
193
119
  precision highp int;
194
120
  precision highp sampler2D;
@@ -209,11 +135,11 @@ uniform mat4 projection_matrix;
209
135
  uniform vec3 camera_position;
210
136
  uniform sampler2D position_tex;
211
137
  uniform sampler2D height_width_angle_tex;
212
- uniform int layer_lo; // 25단계: 이중 슬라이더 하한(레이어). 범위 밖 세그먼트는 셰이더가 O(1) 클립.
213
- uniform int layer_hi; // 상한은 instanceCount 로 컷(레이어 순 정렬).
138
+ uniform int layer_lo; // stage 25: dual slider lower bound (layer). The shader clips out-of-range segments in O(1).
139
+ uniform int layer_hi; // the upper bound is cut via instanceCount (sorted by layer).
214
140
  in float vertex_id_float;
215
- in uint seg_id_a_u; // 인스턴스 어트리뷰트(구 segment_index_tex.r) — 어트리뷰트 fetch 가 texelFetch 보다 쌈
216
- in uint seg_layer_u; // 인스턴스 어트리뷰트(구 segment_index_tex.g)
141
+ in uint seg_id_a_u; // instance attribute (formerly segment_index_tex.r) — attribute fetch is cheaper than texelFetch
142
+ in uint seg_layer_u; // instance attribute (formerly segment_index_tex.g)
217
143
  out vec3 color;
218
144
  vec3 decode_color(float col) {
219
145
  int c = int(round(col));
@@ -236,7 +162,7 @@ ivec2 tex_coord(sampler2D sampler, int id) {
236
162
  void main() {
237
163
  int vertex_id = int(vertex_id_float);
238
164
  int seg_layer = int(seg_layer_u);
239
- if (seg_layer < layer_lo || seg_layer > layer_hi) { gl_Position = vec4(2.0, 2.0, 2.0, 1.0); return; } // 범위 밖 → 클립
165
+ if (seg_layer < layer_lo || seg_layer > layer_hi) { gl_Position = vec4(2.0, 2.0, 2.0, 1.0); return; } // out of range -> clip
240
166
  int id_a = int(seg_id_a_u);
241
167
  int id_b = id_a + 1;
242
168
  vec3 pos_a = texelFetch(position_tex, tex_coord(position_tex, id_a), 0).xyz;
@@ -308,22 +234,51 @@ void main() {
308
234
  color = color_base * lighting(eye_position, eye_normal);
309
235
  gl_Position = projection_matrix * vec4(eye_position, 1.0);
310
236
  }
311
- `, pe = `
237
+ `, de = `
312
238
  precision highp float;
313
239
  in vec3 color;
314
240
  out vec4 fragment_color;
315
241
  void main() {
316
242
  fragment_color = vec4(color, 1.0);
317
243
  }
318
- `;
319
- function me(t, i) {
244
+ `, fe = [
245
+ 0,
246
+ 1,
247
+ 2,
248
+ 0,
249
+ 2,
250
+ 3,
251
+ // front spike
252
+ 0,
253
+ 3,
254
+ 4,
255
+ 0,
256
+ 4,
257
+ 5,
258
+ // right/bottom body
259
+ 0,
260
+ 5,
261
+ 6,
262
+ 0,
263
+ 6,
264
+ 1,
265
+ // left/top body
266
+ 5,
267
+ 4,
268
+ 7,
269
+ 5,
270
+ 7,
271
+ 6
272
+ // back spike
273
+ ];
274
+ function ge(t, i) {
320
275
  const s = (c, d) => {
321
- const u = Math.min(2048, Math.max(1, d)), f = Math.max(1, Math.ceil(d / u)), C = new Float32Array(u * f * 4);
322
- C.set(c.subarray(0, Math.min(c.length, u * f * 4)));
323
- const z = new t.DataTexture(C, u, f, t.RGBAFormat, t.FloatType);
276
+ const p = Math.min(2048, Math.max(1, d)), f = Math.max(1, Math.ceil(d / p)), C = new Float32Array(p * f * 4);
277
+ C.set(c.subarray(0, Math.min(c.length, p * f * 4)));
278
+ const z = new t.DataTexture(C, p, f, t.RGBAFormat, t.FloatType);
324
279
  return z.minFilter = z.magFilter = t.NearestFilter, z.generateMipmaps = !1, z.needsUpdate = !0, z;
325
280
  }, n = s(i.position, i.nV), l = s(i.hwa, i.nV), a = new t.InstancedBufferGeometry();
326
- a.setIndex(le), a.setAttribute("position", new t.BufferAttribute(new Float32Array(8 * 3), 3)), a.setAttribute("vertex_id_float", new t.BufferAttribute(new Float32Array([0, 1, 2, 3, 4, 5, 6, 7]), 1));
281
+ a.setIndex(fe), a.setAttribute("position", new t.BufferAttribute(new Float32Array(8 * 3), 3)), a.setAttribute("vertex_id_float", new t.BufferAttribute(new Float32Array([0, 1, 2, 3, 4, 5, 6, 7]), 1));
327
282
  const h = new t.InstancedInterleavedBuffer(i.segIndex, 4);
328
283
  a.setAttribute("seg_id_a_u", new t.InterleavedBufferAttribute(h, 1, 0)), a.setAttribute("seg_layer_u", new t.InterleavedBufferAttribute(h, 1, 1)), a.instanceCount = 0;
329
284
  const _ = new t.RawShaderMaterial({
@@ -337,50 +292,94 @@ function me(t, i) {
337
292
  layer_lo: { value: 0 },
338
293
  layer_hi: { value: i.layerCount }
339
294
  },
340
- vertexShader: fe,
341
- fragmentShader: pe,
295
+ vertexShader: he,
296
+ fragmentShader: de,
342
297
  side: t.DoubleSide
343
298
  }), y = new t.Mesh(a, _);
344
299
  let v = null;
345
300
  if (i.bbox) {
346
- const { min: c, max: d } = i.bbox, u = new t.Vector3((c[0] + d[0]) / 2, (c[1] + d[1]) / 2, (c[2] + d[2]) / 2), f = Math.hypot(d[0] - c[0], d[1] - c[1], d[2] - c[2]) / 2 + 2;
347
- v = new t.Sphere(u, f);
301
+ const { min: c, max: d } = i.bbox, p = new t.Vector3((c[0] + d[0]) / 2, (c[1] + d[1]) / 2, (c[2] + d[2]) / 2), f = Math.hypot(d[0] - c[0], d[1] - c[1], d[2] - c[2]) / 2 + 2;
302
+ v = new t.Sphere(p, f);
348
303
  }
349
304
  y.frustumCulled = !!v, v && (a.boundingSphere = v);
350
305
  const r = new t.Matrix4(), x = new t.Vector3();
351
- y.onBeforeRender = (c, d, u) => {
352
- _.uniforms.projection_matrix.value.copy(u.projectionMatrix), _.uniforms.view_matrix.value.multiplyMatrices(u.matrixWorldInverse, y.matrixWorld), r.copy(y.matrixWorld).invert(), u.getWorldPosition(x).applyMatrix4(r), _.uniforms.camera_position.value.copy(x);
306
+ y.onBeforeRender = (c, d, p) => {
307
+ _.uniforms.projection_matrix.value.copy(p.projectionMatrix), _.uniforms.view_matrix.value.multiplyMatrices(p.matrixWorldInverse, y.matrixWorld), r.copy(y.matrixWorld).invert(), p.getWorldPosition(x).applyMatrix4(r), _.uniforms.camera_position.value.copy(x);
353
308
  };
354
309
  const b = new t.BufferGeometry();
355
310
  b.setAttribute("position", new t.BufferAttribute(i.travelPos, 3)), b.setDrawRange(0, 0);
356
311
  const A = new t.LineSegments(b, new t.LineBasicMaterial({ color: 7041658 }));
357
312
  A.frustumCulled = !!v, A.visible = !1, v && (b.boundingSphere = v);
358
313
  let M = !1, L = 0, P = i.layerCount - 1;
359
- const k = () => {
314
+ const D = () => {
360
315
  const c = i.travelPrefix[L], d = i.travelPrefix[P + 1];
361
316
  b.setDrawRange(M ? c * 2 : 0, M ? (d - c) * 2 : 0);
362
317
  }, W = (c, d) => {
363
- const u = i.layerCount;
364
- L = Math.max(0, Math.min(u - 1, c | 0)), P = Math.max(L, Math.min(u - 1, d | 0)), _.uniforms.layer_lo.value = L, _.uniforms.layer_hi.value = P, a.instanceCount = i.layerSegPrefix[P + 1], k();
318
+ const p = i.layerCount;
319
+ L = Math.max(0, Math.min(p - 1, c | 0)), P = Math.max(L, Math.min(p - 1, d | 0)), _.uniforms.layer_lo.value = L, _.uniforms.layer_hi.value = P, a.instanceCount = i.layerSegPrefix[P + 1], D();
365
320
  };
366
321
  return { mesh: y, travLines: A, setVisibleLayers: (c) => W(0, (c | 0) - 1), setLayerRange: W, setTravelVisible: (c) => {
367
- M = !!c, A.visible = M, k();
322
+ M = !!c, A.visible = M, D();
368
323
  }, setColors: (c) => {
369
- const d = l.image.data, u = Math.min(c.length, d.length) / 4;
370
- for (let f = 0; f < u; f++) d[f * 4 + 3] = c[f * 4];
324
+ const d = l.image.data, p = Math.min(c.length, d.length) / 4;
325
+ for (let f = 0; f < p; f++) d[f * 4 + 3] = c[f * 4];
371
326
  l.needsUpdate = !0;
372
327
  }, dispose: () => {
373
328
  a.dispose(), _.dispose(), n.dispose(), l.dispose(), b.dispose(), A.material.dispose();
374
329
  }, nSeg: i.nSeg, layerCount: i.layerCount };
375
330
  }
331
+ const ae = [
332
+ { key: "feature", label: "Feature type", cont: !1, unit: "" },
333
+ { key: "speed", label: "Speed", cont: !0, unit: "mm/s" },
334
+ { key: "height", label: "Layer Height", cont: !0, unit: "mm" },
335
+ { key: "width", label: "Line Width", cont: !0, unit: "mm" },
336
+ { key: "fan", label: "Fan Speed", cont: !0, unit: "%" },
337
+ { key: "temp", label: "Temperature", cont: !0, unit: "°C" }
338
+ ];
339
+ function ue(t, i, s, n) {
340
+ const l = i.vType[s], a = i.vLayer[s], h = a === 0;
341
+ switch (t) {
342
+ case "height":
343
+ return i.vHeight[s];
344
+ case "width":
345
+ return i.vWidth[s];
346
+ case "speed":
347
+ return h ? n.firstLayerSpeed : n.speedByType[l] ?? n.speedByType[1];
348
+ case "fan":
349
+ return a < n.closeFanLayers ? 0 : l === 9 ? 100 : n.fanNormal;
350
+ case "temp":
351
+ return h ? n.tempFirst : n.tempNormal;
352
+ default:
353
+ return 0;
354
+ }
355
+ }
356
+ function me(t, i, s) {
357
+ const { meta: n, nV: l } = t, a = new Float32Array(l * 4), h = ae.find((r) => r.key === i) || ae[0];
358
+ if (!h.cont) {
359
+ for (let r = 0; r < l; r++) a[r * 4] = ie(U[n.vType[r]] || U[1]);
360
+ return { color: a, min: 0, max: 0, viewType: i, label: h.label, unit: h.unit, cont: !1 };
361
+ }
362
+ let _ = 1 / 0, y = -1 / 0;
363
+ const v = new Float32Array(l);
364
+ for (let r = 0; r < l; r++) {
365
+ const x = ue(i, n, r, s);
366
+ v[r] = x, x < _ && (_ = x), x > y && (y = x);
367
+ }
368
+ Number.isFinite(_) || (_ = 0, y = 1);
369
+ for (let r = 0; r < l; r++) {
370
+ const x = ce(v[r], _, y, _e);
371
+ a[r * 4] = ie(x);
372
+ }
373
+ return { color: a, min: _, max: y, viewType: i, label: h.label, unit: h.unit, cont: !0 };
374
+ }
376
375
  export {
377
- ce as DEFAULT_RANGES_COLORS,
376
+ _e as DEFAULT_RANGES_COLORS,
378
377
  U as TYPE_COLOR,
379
- _e as TYPE_LABEL,
380
- le as VERTEX_DATA,
378
+ le as TYPE_LABEL,
379
+ fe as VERTEX_DATA,
381
380
  ae as VIEW_TYPES,
382
- ue as buildSegmentData,
383
- ge as computeColors,
384
- me as makeToolpath,
381
+ pe as buildSegmentData,
382
+ me as computeColors,
383
+ ge as makeToolpath,
385
384
  ve as roleRatios
386
385
  };