three-slicer 0.1.0
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/LICENSE.txt +661 -0
- package/README.md +44 -0
- package/components/README.md +39 -0
- package/components/dist/SettingsPanel.js +180 -0
- package/components/styles.css +84 -0
- package/data/README.md +22 -0
- package/data/config-schema-builddump.json +12921 -0
- package/data/config-schema.json +12685 -0
- package/data/invalidation-map.json +631 -0
- package/data/toggle-rules.json +2277 -0
- package/data/ui-tree.json +1586 -0
- package/engine/README.md +52 -0
- package/engine/examples/headless.mjs +37 -0
- package/engine/index.d.ts +29 -0
- package/engine/index.js +45 -0
- package/engine/src/settings.js +130 -0
- package/engine/src/slicer.worker.js +73 -0
- package/engine/src/slicer_core.js +0 -0
- package/engine/src/slicer_core.mt.js +0 -0
- package/engine/src/toggle_eval.js +78 -0
- package/package.json +74 -0
- package/viewer/README.md +68 -0
- package/viewer/dist/Viewport.js +1108 -0
- package/viewer/dist/make_worker.js +9 -0
- package/viewer/dist/model_loaders.js +144 -0
- package/viewer/dist/toolpath_gpu.js +386 -0
- package/viewer/src/Viewport.jsx +1353 -0
- package/viewer/src/assets/add.svg +1 -0
- package/viewer/src/assets/arrange.svg +1 -0
- package/viewer/src/assets/boolean.svg +1 -0
- package/viewer/src/assets/cut.svg +1 -0
- package/viewer/src/assets/delete.svg +1 -0
- package/viewer/src/assets/deleteall.svg +1 -0
- package/viewer/src/assets/duplicate.svg +1 -0
- package/viewer/src/assets/measure.svg +1 -0
- package/viewer/src/assets/mmu.svg +1 -0
- package/viewer/src/assets/move.svg +1 -0
- package/viewer/src/assets/negative.svg +1 -0
- package/viewer/src/assets/onbed.svg +1 -0
- package/viewer/src/assets/open.svg +1 -0
- package/viewer/src/assets/orient.svg +1 -0
- package/viewer/src/assets/paint.svg +1 -0
- package/viewer/src/assets/rotate.svg +1 -0
- package/viewer/src/assets/scale.svg +1 -0
- package/viewer/src/assets/seam.svg +1 -0
- package/viewer/src/assets/split.svg +1 -0
- package/viewer/src/assets/textmark.svg +1 -0
- package/viewer/src/assets/varlayer.svg +1 -0
- package/viewer/src/icons.js +23 -0
- package/viewer/src/make_worker.js +9 -0
- package/viewer/src/model_loaders.js +178 -0
- package/viewer/src/shadow_host.jsx +30 -0
- package/viewer/src/toolpath_gpu.js +430 -0
- package/viewer/styles.css +231 -0
|
@@ -0,0 +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 패키지로 해석된다.
|
|
7
|
+
export function makeSlicerWorker() {
|
|
8
|
+
return new Worker(new URL('../../engine/src/slicer.worker.js', import.meta.url), { type: 'module' })
|
|
9
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import * as T from "three";
|
|
2
|
+
import { OBJLoader as E } from "three/examples/jsm/loaders/OBJLoader.js";
|
|
3
|
+
import { PLYLoader as F } from "three/examples/jsm/loaders/PLYLoader.js";
|
|
4
|
+
import { ThreeMFLoader as x } from "three/examples/jsm/loaders/3MFLoader.js";
|
|
5
|
+
import { AMFLoader as L } from "three/examples/jsm/loaders/AMFLoader.js";
|
|
6
|
+
const O = ["stl", "obj", "3mf", "amf", "ply"];
|
|
7
|
+
function A(e) {
|
|
8
|
+
const o = e.lastIndexOf(".");
|
|
9
|
+
return o < 0 ? "" : e.slice(o + 1).toLowerCase();
|
|
10
|
+
}
|
|
11
|
+
function v(e) {
|
|
12
|
+
const o = new DataView(e);
|
|
13
|
+
if (e.byteLength >= 84) {
|
|
14
|
+
const u = o.getUint32(80, !0);
|
|
15
|
+
if (e.byteLength === 84 + u * 50) {
|
|
16
|
+
const c = new Float32Array(u * 9);
|
|
17
|
+
let a = 84, p = 0;
|
|
18
|
+
for (let d = 0; d < u; d++) {
|
|
19
|
+
a += 12;
|
|
20
|
+
for (let t = 0; t < 3; t++)
|
|
21
|
+
c[p++] = o.getFloat32(a, !0), c[p++] = o.getFloat32(a + 4, !0), c[p++] = o.getFloat32(a + 8, !0), a += 12;
|
|
22
|
+
a += 2;
|
|
23
|
+
}
|
|
24
|
+
return c;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const l = new TextDecoder().decode(e), n = /vertex\s+([-\d.eE+]+)\s+([-\d.eE+]+)\s+([-\d.eE+]+)/g, r = [];
|
|
28
|
+
let i;
|
|
29
|
+
for (; i = n.exec(l); ) r.push(+i[1], +i[2], +i[3]);
|
|
30
|
+
return r.length < 9 ? null : new Float32Array(r);
|
|
31
|
+
}
|
|
32
|
+
function y(e, o) {
|
|
33
|
+
var p;
|
|
34
|
+
const l = (p = e == null ? void 0 : e.attributes) == null ? void 0 : p.position;
|
|
35
|
+
if (!l || l.count < 3) return null;
|
|
36
|
+
const n = e.index, r = new T.Vector3(), i = Math.floor((n ? n.count : l.count) / 3), u = new Float32Array(i * 9);
|
|
37
|
+
let c = 0;
|
|
38
|
+
const a = (d) => {
|
|
39
|
+
r.fromBufferAttribute(l, d), o && r.applyMatrix4(o), u[c++] = r.x, u[c++] = r.y, u[c++] = r.z;
|
|
40
|
+
};
|
|
41
|
+
if (n)
|
|
42
|
+
for (let d = 0; d < i * 3; d++) a(n.getX(d));
|
|
43
|
+
else
|
|
44
|
+
for (let d = 0; d < i * 3; d++) a(d);
|
|
45
|
+
return u;
|
|
46
|
+
}
|
|
47
|
+
function m(e) {
|
|
48
|
+
e.updateMatrixWorld(!0);
|
|
49
|
+
const o = [];
|
|
50
|
+
return e.traverse((l) => {
|
|
51
|
+
l.isMesh && l.geometry && o.push({ geometry: l.geometry, matrix: l.matrixWorld });
|
|
52
|
+
}), o;
|
|
53
|
+
}
|
|
54
|
+
function M(e, o, l) {
|
|
55
|
+
const n = o.map((c) => y(c.geometry, c.matrix)).filter(Boolean);
|
|
56
|
+
if (!n.length) return [];
|
|
57
|
+
if (l && n.length > 1)
|
|
58
|
+
return n.map((c, a) => ({ name: `${e}#${a + 1}`, modelPos: c }));
|
|
59
|
+
if (n.length === 1) return [{ name: e, modelPos: n[0] }];
|
|
60
|
+
let r = 0;
|
|
61
|
+
for (const c of n) r += c.length;
|
|
62
|
+
const i = new Float32Array(r);
|
|
63
|
+
let u = 0;
|
|
64
|
+
for (const c of n)
|
|
65
|
+
i.set(c, u), u += c.length;
|
|
66
|
+
return [{ name: e, modelPos: i }];
|
|
67
|
+
}
|
|
68
|
+
async function k(e, o) {
|
|
69
|
+
const l = A(e);
|
|
70
|
+
switch (l) {
|
|
71
|
+
case "stl": {
|
|
72
|
+
const n = v(o);
|
|
73
|
+
if (!n) throw new Error("STL 파싱 실패");
|
|
74
|
+
return [{ name: e, modelPos: n }];
|
|
75
|
+
}
|
|
76
|
+
case "obj": {
|
|
77
|
+
const n = new E().parse(new TextDecoder().decode(o));
|
|
78
|
+
return M(e, m(n), !1);
|
|
79
|
+
}
|
|
80
|
+
case "ply": {
|
|
81
|
+
const n = new F().parse(o), r = y(n, null);
|
|
82
|
+
if (!r) throw new Error("PLY 지오메트리 없음");
|
|
83
|
+
return [{ name: e, modelPos: r }];
|
|
84
|
+
}
|
|
85
|
+
case "3mf": {
|
|
86
|
+
const n = new x().parse(o), r = M(e, m(n), !0);
|
|
87
|
+
if (!r.length) throw new Error("3MF 메시 없음");
|
|
88
|
+
return r;
|
|
89
|
+
}
|
|
90
|
+
case "amf": {
|
|
91
|
+
const n = new L().parse(o), r = M(e, m(n), !0);
|
|
92
|
+
if (!r.length) throw new Error("AMF 메시 없음");
|
|
93
|
+
return r;
|
|
94
|
+
}
|
|
95
|
+
default:
|
|
96
|
+
throw new Error(`지원하지 않는 포맷: .${l} (STEP 은 범위 외 — OCCT 필요)`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function D(e) {
|
|
100
|
+
const o = Math.floor(e.length / 9);
|
|
101
|
+
if (o < 2) return null;
|
|
102
|
+
const l = 1e4, n = /* @__PURE__ */ new Map(), r = new Int32Array(o * 3);
|
|
103
|
+
for (let t = 0; t < o; t++)
|
|
104
|
+
for (let s = 0; s < 3; s++) {
|
|
105
|
+
const f = t * 9 + s * 3, w = `${Math.round(e[f] * l)},${Math.round(e[f + 1] * l)},${Math.round(e[f + 2] * l)}`;
|
|
106
|
+
let h = n.get(w);
|
|
107
|
+
h === void 0 && (h = n.size, n.set(w, h)), r[t * 3 + s] = h;
|
|
108
|
+
}
|
|
109
|
+
const i = new Int32Array(o);
|
|
110
|
+
for (let t = 0; t < o; t++) i[t] = t;
|
|
111
|
+
const u = (t) => {
|
|
112
|
+
for (; i[t] !== t; )
|
|
113
|
+
i[t] = i[i[t]], t = i[t];
|
|
114
|
+
return t;
|
|
115
|
+
}, c = (t, s) => {
|
|
116
|
+
t = u(t), s = u(s), t !== s && (i[s] = t);
|
|
117
|
+
}, a = /* @__PURE__ */ new Map();
|
|
118
|
+
for (let t = 0; t < o; t++)
|
|
119
|
+
for (let s = 0; s < 3; s++) {
|
|
120
|
+
const f = r[t * 3 + s], w = r[t * 3 + (s + 1) % 3], h = f < w ? f * 4294967296 + w : w * 4294967296 + f, g = a.get(h);
|
|
121
|
+
g === void 0 ? a.set(h, t) : c(t, g);
|
|
122
|
+
}
|
|
123
|
+
const p = /* @__PURE__ */ new Map();
|
|
124
|
+
for (let t = 0; t < o; t++) {
|
|
125
|
+
const s = u(t);
|
|
126
|
+
let f = p.get(s);
|
|
127
|
+
f || (f = [], p.set(s, f)), f.push(t);
|
|
128
|
+
}
|
|
129
|
+
return p.size < 2 ? null : [...p.values()].sort((t, s) => s.length - t.length).map((t) => {
|
|
130
|
+
const s = new Float32Array(t.length * 9);
|
|
131
|
+
let f = 0;
|
|
132
|
+
for (const w of t) {
|
|
133
|
+
const h = w * 9;
|
|
134
|
+
for (let g = 0; g < 9; g++) s[f++] = e[h + g];
|
|
135
|
+
}
|
|
136
|
+
return s;
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
export {
|
|
140
|
+
O as SUPPORTED_EXT,
|
|
141
|
+
A as fileExt,
|
|
142
|
+
k as loadModel,
|
|
143
|
+
D as splitConnectedComponents
|
|
144
|
+
};
|
|
@@ -0,0 +1,386 @@
|
|
|
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 = {
|
|
31
|
+
0: [0.42, 0.45, 0.5],
|
|
32
|
+
1: [0.85, 0.51, 0.17],
|
|
33
|
+
2: [0.21, 0.45, 0.76],
|
|
34
|
+
3: [0.35, 0.75, 0.85],
|
|
35
|
+
4: [0.16, 0.68, 0.4],
|
|
36
|
+
5: [0.66, 0.42, 0.85],
|
|
37
|
+
6: [0.55, 0.45, 0.35],
|
|
38
|
+
7: [0.95, 0.85, 0.25],
|
|
39
|
+
8: [0.9, 0.35, 0.65],
|
|
40
|
+
9: [0.9, 0.25, 0.25],
|
|
41
|
+
10: [0.6, 0.82, 0.55],
|
|
42
|
+
11: [0.3, 0.72, 0.7]
|
|
43
|
+
};
|
|
44
|
+
function ie(t) {
|
|
45
|
+
const i = Math.round(t[0] * 255), s = Math.round(t[1] * 255), n = Math.round(t[2] * 255);
|
|
46
|
+
return i << 16 | s << 8 | n;
|
|
47
|
+
}
|
|
48
|
+
function ue(t, i) {
|
|
49
|
+
const s = t.length, n = i > 0 ? i : 0.42, l = new Array(s);
|
|
50
|
+
for (let e = 0; e < s; e++) {
|
|
51
|
+
const o = t[e].z;
|
|
52
|
+
l[e] = Math.max(0.02, e === 0 ? o : o - t[e - 1].z);
|
|
53
|
+
}
|
|
54
|
+
const a = [], h = [], _ = [], y = [], v = [], r = [], x = [], b = [], A = [], M = [], L = new Float64Array(16), P = [], k = [];
|
|
55
|
+
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);
|
|
57
|
+
for (let e = 0; e < s; e++) {
|
|
58
|
+
const o = t[e].paths, g = t[e].widths, m = l[e];
|
|
59
|
+
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];
|
|
62
|
+
if (w === 0) {
|
|
63
|
+
P.push(F, I, G, S, V, B), k.push(e);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
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);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
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;
|
|
74
|
+
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;
|
|
77
|
+
const w = e > 0 && b[e - 1], F = b[e];
|
|
78
|
+
let I = 0;
|
|
79
|
+
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);
|
|
82
|
+
}
|
|
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);
|
|
84
|
+
}
|
|
85
|
+
const te = new Uint32Array(C * 4);
|
|
86
|
+
for (let e = 0; e < C; e++)
|
|
87
|
+
te[e * 4] = A[e], te[e * 4 + 1] = M[e];
|
|
88
|
+
const K = { vType: new Uint8Array(f), vWidth: new Float32Array(f), vHeight: new Float32Array(f), vLayer: new Int32Array(f) };
|
|
89
|
+
for (let e = 0; e < f; e++)
|
|
90
|
+
K.vType[e] = r[e], K.vWidth[e] = v[e], K.vHeight[e] = y[e], K.vLayer[e] = x[e];
|
|
91
|
+
const oe = new Int32Array(s + 1);
|
|
92
|
+
{
|
|
93
|
+
let e = 0;
|
|
94
|
+
for (let o = 0; o < s; o++) {
|
|
95
|
+
for (; e < C && M[e] === o; ) e++;
|
|
96
|
+
oe[o + 1] = e;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const Q = k.length, N = new Float32Array(Q * 6);
|
|
100
|
+
for (let e = 0; e < N.length; e++) N[e] = P[e];
|
|
101
|
+
for (let e = 0; e < N.length; e += 3) {
|
|
102
|
+
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);
|
|
104
|
+
}
|
|
105
|
+
const re = new Int32Array(s + 1);
|
|
106
|
+
{
|
|
107
|
+
let e = 0;
|
|
108
|
+
for (let o = 0; o < s; o++) {
|
|
109
|
+
for (; e < Q && k[e] === o; ) e++;
|
|
110
|
+
re[o + 1] = e;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const se = f + Q > 0 ? { min: [j, T, X], max: [Z, q, J] } : null;
|
|
114
|
+
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
|
+
}
|
|
116
|
+
const _e = { 1: "벽", 2: "스파스", 3: "솔리드", 4: "스커트", 5: "서포트", 6: "래프트", 7: "갭필", 8: "씬월", 9: "브리지", 10: "아이어닝", 11: "프라임" };
|
|
117
|
+
function ve(t) {
|
|
118
|
+
let i = 0;
|
|
119
|
+
for (let n = 1; n < 16; n++) i += t[n] || 0;
|
|
120
|
+
const s = [];
|
|
121
|
+
if (i <= 0) return s;
|
|
122
|
+
for (let n = 1; n < 16; n++) {
|
|
123
|
+
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] });
|
|
125
|
+
}
|
|
126
|
+
return s.sort((n, l) => l.pct - n.pct);
|
|
127
|
+
}
|
|
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 = `
|
|
192
|
+
precision highp float;
|
|
193
|
+
precision highp int;
|
|
194
|
+
precision highp sampler2D;
|
|
195
|
+
precision highp usampler2D;
|
|
196
|
+
#define POINTY_CAPS
|
|
197
|
+
#define FIX_TWISTING
|
|
198
|
+
const vec3 light_top_dir = vec3(-0.4574957, 0.4574957, 0.7624929);
|
|
199
|
+
const float light_top_diffuse = 0.6 * 0.8;
|
|
200
|
+
const float light_top_specular = 0.6 * 0.125;
|
|
201
|
+
const float light_top_shininess = 20.0;
|
|
202
|
+
const vec3 light_front_dir = vec3(0.6985074, 0.1397015, 0.6985074);
|
|
203
|
+
const float light_front_diffuse = 0.6 * 0.3;
|
|
204
|
+
const float ambient = 0.3;
|
|
205
|
+
const float emission = 0.15;
|
|
206
|
+
const vec3 UP = vec3(0, 0, 1);
|
|
207
|
+
uniform mat4 view_matrix;
|
|
208
|
+
uniform mat4 projection_matrix;
|
|
209
|
+
uniform vec3 camera_position;
|
|
210
|
+
uniform sampler2D position_tex;
|
|
211
|
+
uniform sampler2D height_width_angle_tex;
|
|
212
|
+
uniform int layer_lo; // 25단계: 이중 슬라이더 하한(레이어). 범위 밖 세그먼트는 셰이더가 O(1) 클립.
|
|
213
|
+
uniform int layer_hi; // 상한은 instanceCount 로 컷(레이어 순 정렬).
|
|
214
|
+
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)
|
|
217
|
+
out vec3 color;
|
|
218
|
+
vec3 decode_color(float col) {
|
|
219
|
+
int c = int(round(col));
|
|
220
|
+
int r = (c >> 16) & 0xFF;
|
|
221
|
+
int g = (c >> 8) & 0xFF;
|
|
222
|
+
int b = (c >> 0) & 0xFF;
|
|
223
|
+
float f = 1.0 / 255.0;
|
|
224
|
+
return f * vec3(r, g, b);
|
|
225
|
+
}
|
|
226
|
+
float lighting(vec3 eye_position, vec3 eye_normal) {
|
|
227
|
+
float top_diffuse = light_top_diffuse * max(dot(eye_normal, light_top_dir), 0.0);
|
|
228
|
+
float front_diffuse = light_front_diffuse * max(dot(eye_normal, light_front_dir), 0.0);
|
|
229
|
+
float top_specular = light_top_specular * pow(max(dot(-normalize(eye_position), reflect(-light_top_dir, eye_normal)), 0.0), light_top_shininess);
|
|
230
|
+
return ambient + top_diffuse + front_diffuse + top_specular + emission;
|
|
231
|
+
}
|
|
232
|
+
ivec2 tex_coord(sampler2D sampler, int id) {
|
|
233
|
+
ivec2 tex_size = textureSize(sampler, 0);
|
|
234
|
+
return (tex_size.y == 1) ? ivec2(id, 0) : ivec2(id % tex_size.x, id / tex_size.x);
|
|
235
|
+
}
|
|
236
|
+
void main() {
|
|
237
|
+
int vertex_id = int(vertex_id_float);
|
|
238
|
+
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; } // 범위 밖 → 클립
|
|
240
|
+
int id_a = int(seg_id_a_u);
|
|
241
|
+
int id_b = id_a + 1;
|
|
242
|
+
vec3 pos_a = texelFetch(position_tex, tex_coord(position_tex, id_a), 0).xyz;
|
|
243
|
+
vec3 pos_b = texelFetch(position_tex, tex_coord(position_tex, id_b), 0).xyz;
|
|
244
|
+
vec3 line = pos_b - pos_a;
|
|
245
|
+
float line_len = length(line);
|
|
246
|
+
vec3 line_dir;
|
|
247
|
+
if (line_len < 1e-4)
|
|
248
|
+
line_dir = vec3(1.0, 0.0, 0.0);
|
|
249
|
+
else
|
|
250
|
+
line_dir = line / line_len;
|
|
251
|
+
vec3 line_right_dir;
|
|
252
|
+
if (abs(dot(line_dir, UP)) > 0.9) {
|
|
253
|
+
line_right_dir = normalize(cross(vec3(1, 0, 0), line_dir));
|
|
254
|
+
}
|
|
255
|
+
else
|
|
256
|
+
line_right_dir = normalize(cross(line_dir, UP));
|
|
257
|
+
vec3 line_up_dir = normalize(cross(line_right_dir, line_dir));
|
|
258
|
+
const vec2 horizontal_vertical_view_signs_array[16] = vec2[](
|
|
259
|
+
vec2(1.0, 0.0), vec2(0.0, 1.0), vec2(0.0, 0.0), vec2(0.0, -1.0),
|
|
260
|
+
vec2(0.0, -1.0), vec2(1.0, 0.0), vec2(0.0, 1.0), vec2(0.0, 0.0),
|
|
261
|
+
vec2(0.0, 1.0), vec2(-1.0, 0.0), vec2(0.0, 0.0), vec2(1.0, 0.0),
|
|
262
|
+
vec2(1.0, 0.0), vec2(0.0, 1.0), vec2(-1.0, 0.0), vec2(0.0, 0.0)
|
|
263
|
+
);
|
|
264
|
+
int id = vertex_id < 4 ? id_a : id_b;
|
|
265
|
+
vec3 endpoint_pos = vertex_id < 4 ? pos_a : pos_b;
|
|
266
|
+
vec4 hwa_color = texelFetch(height_width_angle_tex, tex_coord(height_width_angle_tex, id), 0); // .xyz=h/w/angle, .w=packed color
|
|
267
|
+
vec3 height_width_angle = hwa_color.xyz;
|
|
268
|
+
#ifdef FIX_TWISTING
|
|
269
|
+
int closer_id = (dot(camera_position - pos_a, camera_position - pos_a) < dot(camera_position - pos_b, camera_position - pos_b)) ? id_a : id_b;
|
|
270
|
+
vec3 closer_pos = (closer_id == id_a) ? pos_a : pos_b;
|
|
271
|
+
vec3 camera_view_dir = normalize(closer_pos - camera_position);
|
|
272
|
+
vec3 closer_height_width_angle = texelFetch(height_width_angle_tex, tex_coord(height_width_angle_tex, closer_id), 0).xyz;
|
|
273
|
+
vec3 diagonal_dir_border = normalize(closer_height_width_angle.x * line_up_dir + closer_height_width_angle.y * line_right_dir);
|
|
274
|
+
#else
|
|
275
|
+
vec3 camera_view_dir = normalize(endpoint_pos - camera_position);
|
|
276
|
+
vec3 diagonal_dir_border = normalize(height_width_angle.x * line_up_dir + height_width_angle.y * line_right_dir);
|
|
277
|
+
#endif
|
|
278
|
+
bool is_vertical_view = abs(dot(camera_view_dir, line_up_dir)) / abs(dot(diagonal_dir_border, line_up_dir)) >
|
|
279
|
+
abs(dot(camera_view_dir, line_right_dir)) / abs(dot(diagonal_dir_border, line_right_dir));
|
|
280
|
+
vec2 signs = horizontal_vertical_view_signs_array[vertex_id + 8 * int(is_vertical_view)];
|
|
281
|
+
#ifndef POINTY_CAPS
|
|
282
|
+
if (vertex_id == 2 || vertex_id == 7) signs = -horizontal_vertical_view_signs_array[(vertex_id - 2) + 8 * int(is_vertical_view)];
|
|
283
|
+
#endif
|
|
284
|
+
float view_right_sign = sign(dot(-camera_view_dir, line_right_dir));
|
|
285
|
+
float view_top_sign = sign(dot(-camera_view_dir, line_up_dir));
|
|
286
|
+
float half_height = 0.5 * height_width_angle.x;
|
|
287
|
+
float half_width = 0.5 * height_width_angle.y;
|
|
288
|
+
vec3 horizontal_dir = half_width * line_right_dir;
|
|
289
|
+
vec3 vertical_dir = half_height * line_up_dir;
|
|
290
|
+
float horizontal_sign = signs.x * view_right_sign;
|
|
291
|
+
float vertical_sign = signs.y * view_top_sign;
|
|
292
|
+
vec3 pos = endpoint_pos + horizontal_sign * horizontal_dir + vertical_sign * vertical_dir;
|
|
293
|
+
if (vertex_id == 2 || vertex_id == 7) {
|
|
294
|
+
float line_dir_sign = (vertex_id == 2) ? -1.0 : 1.0;
|
|
295
|
+
if (height_width_angle.z == 0.0) {
|
|
296
|
+
#ifdef POINTY_CAPS
|
|
297
|
+
pos += line_dir_sign * line_dir * half_width;
|
|
298
|
+
#endif
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
pos += line_dir_sign * line_dir * half_width * sin(abs(height_width_angle.z) * 0.5);
|
|
302
|
+
pos += sign(height_width_angle.z) * horizontal_dir * cos(abs(height_width_angle.z) * 0.5);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
vec3 eye_position = (view_matrix * vec4(pos, 1.0)).xyz;
|
|
306
|
+
vec3 eye_normal = (view_matrix * vec4(normalize(pos - endpoint_pos), 0.0)).xyz;
|
|
307
|
+
vec3 color_base = decode_color(hwa_color.w);
|
|
308
|
+
color = color_base * lighting(eye_position, eye_normal);
|
|
309
|
+
gl_Position = projection_matrix * vec4(eye_position, 1.0);
|
|
310
|
+
}
|
|
311
|
+
`, pe = `
|
|
312
|
+
precision highp float;
|
|
313
|
+
in vec3 color;
|
|
314
|
+
out vec4 fragment_color;
|
|
315
|
+
void main() {
|
|
316
|
+
fragment_color = vec4(color, 1.0);
|
|
317
|
+
}
|
|
318
|
+
`;
|
|
319
|
+
function me(t, i) {
|
|
320
|
+
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);
|
|
324
|
+
return z.minFilter = z.magFilter = t.NearestFilter, z.generateMipmaps = !1, z.needsUpdate = !0, z;
|
|
325
|
+
}, 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));
|
|
327
|
+
const h = new t.InstancedInterleavedBuffer(i.segIndex, 4);
|
|
328
|
+
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
|
+
const _ = new t.RawShaderMaterial({
|
|
330
|
+
glslVersion: t.GLSL3,
|
|
331
|
+
uniforms: {
|
|
332
|
+
view_matrix: { value: new t.Matrix4() },
|
|
333
|
+
projection_matrix: { value: new t.Matrix4() },
|
|
334
|
+
camera_position: { value: new t.Vector3() },
|
|
335
|
+
position_tex: { value: n },
|
|
336
|
+
height_width_angle_tex: { value: l },
|
|
337
|
+
layer_lo: { value: 0 },
|
|
338
|
+
layer_hi: { value: i.layerCount }
|
|
339
|
+
},
|
|
340
|
+
vertexShader: fe,
|
|
341
|
+
fragmentShader: pe,
|
|
342
|
+
side: t.DoubleSide
|
|
343
|
+
}), y = new t.Mesh(a, _);
|
|
344
|
+
let v = null;
|
|
345
|
+
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);
|
|
348
|
+
}
|
|
349
|
+
y.frustumCulled = !!v, v && (a.boundingSphere = v);
|
|
350
|
+
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);
|
|
353
|
+
};
|
|
354
|
+
const b = new t.BufferGeometry();
|
|
355
|
+
b.setAttribute("position", new t.BufferAttribute(i.travelPos, 3)), b.setDrawRange(0, 0);
|
|
356
|
+
const A = new t.LineSegments(b, new t.LineBasicMaterial({ color: 7041658 }));
|
|
357
|
+
A.frustumCulled = !!v, A.visible = !1, v && (b.boundingSphere = v);
|
|
358
|
+
let M = !1, L = 0, P = i.layerCount - 1;
|
|
359
|
+
const k = () => {
|
|
360
|
+
const c = i.travelPrefix[L], d = i.travelPrefix[P + 1];
|
|
361
|
+
b.setDrawRange(M ? c * 2 : 0, M ? (d - c) * 2 : 0);
|
|
362
|
+
}, 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();
|
|
365
|
+
};
|
|
366
|
+
return { mesh: y, travLines: A, setVisibleLayers: (c) => W(0, (c | 0) - 1), setLayerRange: W, setTravelVisible: (c) => {
|
|
367
|
+
M = !!c, A.visible = M, k();
|
|
368
|
+
}, 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];
|
|
371
|
+
l.needsUpdate = !0;
|
|
372
|
+
}, dispose: () => {
|
|
373
|
+
a.dispose(), _.dispose(), n.dispose(), l.dispose(), b.dispose(), A.material.dispose();
|
|
374
|
+
}, nSeg: i.nSeg, layerCount: i.layerCount };
|
|
375
|
+
}
|
|
376
|
+
export {
|
|
377
|
+
ce as DEFAULT_RANGES_COLORS,
|
|
378
|
+
U as TYPE_COLOR,
|
|
379
|
+
_e as TYPE_LABEL,
|
|
380
|
+
le as VERTEX_DATA,
|
|
381
|
+
ae as VIEW_TYPES,
|
|
382
|
+
ue as buildSegmentData,
|
|
383
|
+
ge as computeColors,
|
|
384
|
+
me as makeToolpath,
|
|
385
|
+
ve as roleRatios
|
|
386
|
+
};
|