printbench 0.7.1 → 0.8.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.
@@ -0,0 +1,294 @@
1
+ import { Vector3 as Y, LoadingManager as N, Color as O } from "three";
2
+ import { DRACOLoader as _ } from "three/examples/jsm/loaders/DRACOLoader.js";
3
+ import { GLTFLoader as z } from "three/examples/jsm/loaders/GLTFLoader.js";
4
+ import { MeshoptDecoder as B } from "three/examples/jsm/libs/meshopt_decoder.module.js";
5
+ import { STLLoader as W } from "three/examples/jsm/loaders/STLLoader.js";
6
+ import { OBJLoader as $ } from "three/examples/jsm/loaders/OBJLoader.js";
7
+ import { ThreeMFLoader as j } from "three/examples/jsm/loaders/3MFLoader.js";
8
+ import A from "jszip";
9
+ import { w as D, u as F } from "./index-Ci-Js4Ma.js";
10
+ import { A as he } from "./index-Ci-Js4Ma.js";
11
+ import { parse3mfMeshObjects as S } from "./3mf-BC6RlyAs.js";
12
+ const I = new URL("../assets/draco_wasm_wrapper.js", import.meta.url).href, X = new URL("../assets/draco_decoder.wasm", import.meta.url).href;
13
+ let b = null;
14
+ function G(e) {
15
+ return e.split("?")[0]?.split("/").pop() ?? e;
16
+ }
17
+ function J() {
18
+ const e = new N();
19
+ e.setURLModifier((a) => {
20
+ const m = G(a);
21
+ return m === "draco_wasm_wrapper.js" ? I : m === "draco_decoder.wasm" ? X : a;
22
+ });
23
+ const s = new _(e);
24
+ return s.setDecoderConfig({ type: "wasm" }), s.setDecoderPath(""), s;
25
+ }
26
+ function R() {
27
+ const e = new z();
28
+ return b || (b = J()), e.setDRACOLoader(b), e.setMeshoptDecoder(B), e;
29
+ }
30
+ function Z(e) {
31
+ return e ? Array.isArray(e) ? e : [e] : [];
32
+ }
33
+ function x(e) {
34
+ const s = "color" in e ? e.color : void 0;
35
+ return s && s instanceof O ? [s.r, s.g, s.b] : [1, 1, 1];
36
+ }
37
+ function P(e) {
38
+ return ("map" in e ? e.map : void 0) ?? void 0;
39
+ }
40
+ function L(e) {
41
+ return e[0] > 0.97 && e[1] > 0.97 && e[2] > 0.97;
42
+ }
43
+ function k(e) {
44
+ if (!e?.image) return;
45
+ const s = e.image, a = Number(s.width), m = Number(s.height);
46
+ if (!(!a || !m))
47
+ try {
48
+ const r = document.createElement("canvas");
49
+ r.width = a, r.height = m;
50
+ const n = r.getContext("2d");
51
+ return n ? (n.drawImage(e.image, 0, 0, a, m), { canvas: r, flipY: e.flipY }) : void 0;
52
+ } catch {
53
+ return;
54
+ }
55
+ }
56
+ function q(e, s, a, m) {
57
+ const r = (s % 1 + 1) % 1, n = (a % 1 + 1) % 1, u = m ? 1 - n : n, h = Math.min(e.width - 1, Math.max(0, Math.floor(r * e.width))), c = (Math.min(e.height - 1, Math.max(0, Math.floor(u * e.height))) * e.width + h) * 4;
58
+ return [e.data[c] / 255, e.data[c + 1] / 255, e.data[c + 2] / 255];
59
+ }
60
+ function V(e, s, a, m, r, n) {
61
+ const u = new Float32Array(e * 3);
62
+ u.fill(1);
63
+ const h = n.map((c) => {
64
+ if (!c) return;
65
+ const l = c.canvas.getContext("2d");
66
+ if (l)
67
+ return { data: l.getImageData(0, 0, c.canvas.width, c.canvas.height), flipY: c.flipY };
68
+ }), o = (c) => {
69
+ for (const l of m)
70
+ if (c >= l.start && c < l.start + l.count) return l.materialIndex ?? 0;
71
+ return 0;
72
+ };
73
+ for (let c = 0; c < s.length; c += 3) {
74
+ const l = r.length ? Math.max(0, Math.min(r.length - 1, o(c))) : 0, i = h[l], p = r[l] ? x(r[l]) : [1, 1, 1];
75
+ for (let f = 0; f < 3; f++) {
76
+ const d = s[c + f];
77
+ let g = p[0], v = p[1], y = p[2];
78
+ if (i && a && d * 2 + 1 < a.length) {
79
+ const w = q(i.data, a[d * 2], a[d * 2 + 1], i.flipY);
80
+ g *= w[0], v *= w[1], y *= w[2];
81
+ }
82
+ u[d * 3] = g, u[d * 3 + 1] = v, u[d * 3 + 2] = y;
83
+ }
84
+ }
85
+ return u;
86
+ }
87
+ function U(e, s, a, m) {
88
+ const r = e.getAttribute("position");
89
+ if (!r) throw new Error("网格缺少 position 属性");
90
+ const n = e.getIndex(), u = new Float32Array(r.count * 3), h = new Y();
91
+ for (let t = 0; t < r.count; t++)
92
+ h.set(r.getX(t), r.getY(t), r.getZ(t)), a && h.applyMatrix4(a), u[t * 3] = h.x, u[t * 3 + 1] = h.y, u[t * 3 + 2] = h.z;
93
+ let o;
94
+ if (n) {
95
+ o = new Uint32Array(n.count);
96
+ for (let t = 0; t < n.count; t++) o[t] = n.getX(t);
97
+ } else {
98
+ o = new Uint32Array(r.count);
99
+ for (let t = 0; t < r.count; t++) o[t] = t;
100
+ }
101
+ const c = e.getAttribute("color");
102
+ let l;
103
+ if (c) {
104
+ l = new Float32Array(r.count * 3);
105
+ for (let t = 0; t < r.count; t++)
106
+ l[t * 3] = c.getX(t), l[t * 3 + 1] = c.getY(t), l[t * 3 + 2] = c.getZ(t);
107
+ }
108
+ const i = e.getAttribute("uv");
109
+ let p;
110
+ if (i) {
111
+ p = new Float32Array(r.count * 2);
112
+ for (let t = 0; t < r.count; t++)
113
+ p[t * 2] = i.getX(t), p[t * 2 + 1] = i.getY(t);
114
+ }
115
+ const f = Z(m), d = f.map((t) => k(P(t)));
116
+ let g, v, y;
117
+ if (f.length <= 1) {
118
+ if (g = d[0]?.canvas, v = d[0]?.flipY, f[0]) {
119
+ const t = x(f[0]);
120
+ (!L(t) || g) && (y = t);
121
+ }
122
+ } else {
123
+ const t = d.map((M) => M?.canvas).filter((M) => !!M);
124
+ if (new Set(t).size === 1 && t.length === f.length) {
125
+ g = t[0], v = d.find((T) => T)?.flipY;
126
+ const M = x(f[0]);
127
+ (!L(M) || g) && (y = M);
128
+ } else
129
+ l = V(r.count, o, p, e.groups, f, d);
130
+ }
131
+ const w = D(u, o, 1e-5, l, p), E = (() => {
132
+ const t = {};
133
+ if (w.uvs && (t.uvs = w.uvs), w.colors && (t.colors = w.colors), y && (t.baseColor = y), g && (t.texture = g, t.flipY = v), !(!t.texture && !t.colors && !t.baseColor))
134
+ return t;
135
+ })();
136
+ return {
137
+ id: F("mesh"),
138
+ name: s,
139
+ visible: !0,
140
+ buffers: { positions: w.positions, indices: w.indices, colors: w.colors },
141
+ appearance: E
142
+ };
143
+ }
144
+ function H(e, s, a, m) {
145
+ const r = D(s, a, 1e-5);
146
+ return {
147
+ id: F("mesh"),
148
+ name: e,
149
+ visible: !0,
150
+ printColor: m ? [m[0], m[1], m[2]] : void 0,
151
+ buffers: { positions: r.positions, indices: r.indices, colors: r.colors }
152
+ };
153
+ }
154
+ function C(e, s) {
155
+ const a = [];
156
+ let m = 0, r = !1;
157
+ return e.updateMatrixWorld(!0), e.traverse((n) => {
158
+ let u = 0, h = n;
159
+ for (; h; )
160
+ u++, h = h.parent;
161
+ if (m = Math.max(m, u), n.isMesh) {
162
+ const o = n;
163
+ (Array.isArray(o.geometry) ? o.geometry : [o.geometry]).forEach((l, i) => {
164
+ if (!l) return;
165
+ const f = (typeof o.name == "string" ? o.name.trim() : "") || `${s}_${a.length || i}`;
166
+ a.push(U(l, f, o.matrixWorld, o.material));
167
+ }), o.material && (r = !0);
168
+ }
169
+ }), { meshes: a, depth: m, hasMat: r };
170
+ }
171
+ async function K(e) {
172
+ const s = e.name.split(".").pop()?.toLowerCase() ?? "", a = await e.arrayBuffer();
173
+ if (s === "zip") return Q(e, a);
174
+ if (s === "glb" || s === "gltf") {
175
+ const r = await R().parseAsync(a, ""), { meshes: n, depth: u, hasMat: h } = C(r.scene, e.name.replace(/\.[^.]+$/, ""));
176
+ if (!n.length) throw new Error("该文件不包含网格,可能是纯灯光/相机场景");
177
+ const o = n.reduce((l, i) => l + i.buffers.indices.length / 3, 0), c = n.reduce((l, i) => l + i.buffers.positions.length / 3, 0);
178
+ return {
179
+ meshes: n,
180
+ summary: {
181
+ fileName: e.name,
182
+ format: s,
183
+ triangleCount: o,
184
+ vertexCount: c,
185
+ nodeDepth: u,
186
+ hasMaterials: h,
187
+ hasAnimations: (r.animations?.length ?? 0) > 0
188
+ }
189
+ };
190
+ }
191
+ if (s === "stl") {
192
+ const r = new W().parse(a), n = U(r, e.name.replace(/\.[^.]+$/, ""));
193
+ return {
194
+ meshes: [n],
195
+ summary: {
196
+ fileName: e.name,
197
+ format: "stl",
198
+ triangleCount: n.buffers.indices.length / 3,
199
+ vertexCount: n.buffers.positions.length / 3,
200
+ nodeDepth: 1,
201
+ hasMaterials: !1,
202
+ hasAnimations: !1
203
+ }
204
+ };
205
+ }
206
+ if (s === "obj") {
207
+ const m = new TextDecoder().decode(a), n = new $().parse(m), { meshes: u, depth: h, hasMat: o } = C(n, e.name.replace(/\.[^.]+$/, ""));
208
+ if (!u.length) throw new Error("OBJ 中没有可用网格");
209
+ const c = u.reduce((i, p) => i + p.buffers.indices.length / 3, 0), l = u.reduce((i, p) => i + p.buffers.positions.length / 3, 0);
210
+ return {
211
+ meshes: u,
212
+ summary: {
213
+ fileName: e.name,
214
+ format: "obj",
215
+ triangleCount: c,
216
+ vertexCount: l,
217
+ nodeDepth: h,
218
+ hasMaterials: o,
219
+ hasAnimations: !1
220
+ }
221
+ };
222
+ }
223
+ if (s === "3mf") {
224
+ const m = await ee(a), n = (await A.loadAsync(a)).file(/3dmodel\.model$/i)[0], u = n ? await n.async("string") : "", h = u ? S(u) : [];
225
+ let o = [], c = 1, l = !1;
226
+ try {
227
+ const d = new j().parse(a), g = C(d, e.name.replace(/\.[^.]+$/, ""));
228
+ o = g.meshes, c = g.depth, l = g.hasMat;
229
+ } catch {
230
+ o = [];
231
+ }
232
+ if (h.length > o.length ? (o = h.map((f) => H(f.name, f.positions, f.indices, f.printColor)), l = !1, c = 1) : h.length && h.forEach((f, d) => {
233
+ o[d] && (f.name?.trim() && (o[d].name = f.name.trim()), f.printColor && (o[d].printColor = [f.printColor[0], f.printColor[1], f.printColor[2]]));
234
+ }), !o.length) throw new Error("3MF 中没有可用网格");
235
+ const i = o.reduce((f, d) => f + d.buffers.indices.length / 3, 0), p = o.reduce((f, d) => f + d.buffers.positions.length / 3, 0);
236
+ return {
237
+ meshes: o,
238
+ declaredUnit: m,
239
+ summary: {
240
+ fileName: e.name,
241
+ format: "3mf",
242
+ triangleCount: i,
243
+ vertexCount: p,
244
+ nodeDepth: c,
245
+ hasMaterials: l,
246
+ hasAnimations: !1,
247
+ declaredUnit: m
248
+ }
249
+ };
250
+ }
251
+ throw new Error("仅支持 GLB / GLTF / STL / OBJ / 3MF / ZIP");
252
+ }
253
+ async function Q(e, s) {
254
+ const a = await A.loadAsync(s), m = Object.values(a.files).filter(
255
+ (i) => !i.dir && !i.name.startsWith("__MACOSX") && !/(^|\/)\./.test(i.name) && /\.(glb|gltf|stl|obj|3mf)$/i.test(i.name)
256
+ ).sort((i, p) => i.name.localeCompare(p.name, "en"));
257
+ if (!m.length) throw new Error("压缩包中没有 STL / 3MF / OBJ / GLB 模型");
258
+ const r = [];
259
+ let n = !1, u = !1, h = 1, o;
260
+ for (const i of m) {
261
+ const p = await i.async("arraybuffer"), f = i.name.split(/[/\\]/).pop() || i.name, d = await K(new File([p], f));
262
+ r.push(...d.meshes), n = n || d.summary.hasMaterials, u = u || d.summary.hasAnimations, h = Math.max(h, d.summary.nodeDepth), d.declaredUnit && !o && (o = d.declaredUnit);
263
+ }
264
+ if (!r.length) throw new Error("压缩包中没有可用网格");
265
+ const c = r.reduce((i, p) => i + p.buffers.indices.length / 3, 0), l = r.reduce((i, p) => i + p.buffers.positions.length / 3, 0);
266
+ return {
267
+ meshes: r,
268
+ declaredUnit: o,
269
+ summary: {
270
+ fileName: e.name,
271
+ format: "zip",
272
+ triangleCount: c,
273
+ vertexCount: l,
274
+ nodeDepth: h,
275
+ hasMaterials: n,
276
+ hasAnimations: u,
277
+ declaredUnit: o
278
+ }
279
+ };
280
+ }
281
+ async function ee(e) {
282
+ try {
283
+ const a = (await A.loadAsync(e)).file(/3dmodel\.model$/i)[0];
284
+ if (!a) return "mm";
285
+ const n = ((await a.async("string")).match(/unit\s*=\s*"([^"]+)"/i)?.[1] ?? "millimeter").toLowerCase();
286
+ return n.startsWith("micro") ? "mm" : n.startsWith("centi") ? "cm" : n.startsWith("meter") && !n.includes("milli") ? "m" : "mm";
287
+ } catch {
288
+ return "mm";
289
+ }
290
+ }
291
+ export {
292
+ he as ACCEPT_EXT,
293
+ K as loadModelFile
294
+ };
@@ -0,0 +1,49 @@
1
+ import { GLTFLoader as w } from "three/examples/jsm/loaders/GLTFLoader.js";
2
+ import { w as y } from "./index-Ci-Js4Ma.js";
3
+ const A = new URL("../assets/qiu_ao.glb", import.meta.url).href, x = new URL("../assets/qiu_tu_di.glb", import.meta.url).href;
4
+ let l = null, i = null;
5
+ function L(n) {
6
+ n.updateMatrixWorld(!0);
7
+ const r = [], o = [];
8
+ let a = 0;
9
+ if (n.traverse((m) => {
10
+ if (!m.isMesh) return;
11
+ const p = m, u = p.geometry;
12
+ if (!u?.getAttribute("position")) return;
13
+ const s = u.getAttribute("position"), c = u.getIndex(), e = p.matrixWorld.elements;
14
+ for (let t = 0; t < s.count; t++) {
15
+ const f = s.getX(t), d = s.getY(t), g = s.getZ(t);
16
+ r.push(
17
+ e[0] * f + e[4] * d + e[8] * g + e[12],
18
+ e[1] * f + e[5] * d + e[9] * g + e[13],
19
+ e[2] * f + e[6] * d + e[10] * g + e[14]
20
+ );
21
+ }
22
+ if (c)
23
+ for (let t = 0; t < c.count; t++) o.push(a + c.getX(t));
24
+ else
25
+ for (let t = 0; t < s.count; t++) o.push(a + t);
26
+ a += s.count;
27
+ }), !r.length || !o.length) throw new Error("卡扣 GLB 中没有网格");
28
+ return y(new Float32Array(r), new Uint32Array(o));
29
+ }
30
+ async function h(n) {
31
+ const o = await new w().loadAsync(n);
32
+ return L(o.scene);
33
+ }
34
+ async function q() {
35
+ if (l) return l;
36
+ if (i) return i;
37
+ i = (async () => {
38
+ const [n, r] = await Promise.all([h(A), h(x)]);
39
+ return l = { ao: n, tu: r }, l;
40
+ })();
41
+ try {
42
+ return await i;
43
+ } finally {
44
+ i = null;
45
+ }
46
+ }
47
+ export {
48
+ q as loadQiuSnapMeshes
49
+ };
@@ -0,0 +1,44 @@
1
+ import p from "jszip";
2
+ import { Group as u, Mesh as l } from "three";
3
+ import { STLExporter as w } from "three/examples/jsm/exporters/STLExporter.js";
4
+ import { b as m } from "./index-Ci-Js4Ma.js";
5
+ function y(t, o) {
6
+ const e = /* @__PURE__ */ new Set();
7
+ return t.map((n, a) => {
8
+ const f = (n.replace(/[<>:"/\\|?*\u0000-\u001f]/g, "_").replace(/\.+$/g, "").trim() || `part_${a + 1}`).slice(0, 80);
9
+ let r = `${f}.${o}`, i = 2;
10
+ for (; e.has(r.toLowerCase()); )
11
+ r = `${f}_${i}.${o}`, i++;
12
+ return e.add(r.toLowerCase()), r;
13
+ });
14
+ }
15
+ function s(t) {
16
+ const o = new w(), e = new u();
17
+ t.forEach((f) => {
18
+ const r = m(f), i = new l(r);
19
+ e.add(i);
20
+ });
21
+ const n = o.parse(e, { binary: !0 }), a = new Uint8Array(n.byteLength);
22
+ return a.set(new Uint8Array(n.buffer, n.byteOffset, n.byteLength)), a.buffer;
23
+ }
24
+ async function L(t, o, e) {
25
+ if (t.length <= 1)
26
+ return { buf: s(t), name: `${o}.stl`, mime: "model/stl" };
27
+ const n = new p();
28
+ return y(e.length === t.length ? e : t.map((r, i) => `part_${i + 1}`), "stl").forEach((r, i) => {
29
+ const c = s([t[i]]);
30
+ if (!b(c)) throw new Error("导出文件头校验失败");
31
+ n.file(r, c);
32
+ }), { buf: await n.generateAsync({ type: "arraybuffer", compression: "DEFLATE" }), name: `${o}.zip`, mime: "application/zip" };
33
+ }
34
+ function b(t) {
35
+ if (t.byteLength < 84) return !1;
36
+ const e = new DataView(t).getUint32(80, !0);
37
+ return t.byteLength === 84 + e * 50;
38
+ }
39
+ export {
40
+ s as exportBinaryStl,
41
+ L as exportStlPackage,
42
+ y as uniqueExportFileNames,
43
+ b as validateStlHeader
44
+ };