three-slicer-viewer 0.3.0 → 0.3.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.
package/types/gcode.d.ts CHANGED
@@ -11,9 +11,35 @@ export interface GcodeLayer {
11
11
 
12
12
  export interface ParseGcodeResult {
13
13
  layers: GcodeLayer[]
14
- stats: { layers: number; path_segments: number; travel_segments: number; tools: number[] }
14
+ stats: {
15
+ layers: number; path_segments: number; travel_segments: number; filament_mm: number
16
+ /** Tool ids that extruded or were selected. Firmware opcodes above T254 (Bambu's T1000, T255, …) are not tools. */
17
+ tools: number[]
18
+ /** Filament length (mm of E) per tool id — the kernel's own stat name. */
19
+ filament_mm_by_tool: number[]
20
+ /** The file's own palette per tool (`; filament_colour` / `; extruder_colour`), null where it names none. */
21
+ colors?: (string | null)[]
22
+ }
15
23
  }
16
24
 
25
+ /**
26
+ * A result's colour list, one entry per tool: its own palette (`stats.colors`), then the session palette, then the
27
+ * categorical stand-in for a tool neither names. What the toolpath is drawn in and what an export states.
28
+ */
29
+ export function resultToolColors(
30
+ stats: { colors?: (string | null)[]; filament_mm_by_tool?: number[] } | null | undefined,
31
+ sessionColors?: string[] | null,
32
+ ): string[]
33
+
34
+ /** A result's G-code as it is saved: `withFilamentColours` over `resultToolColors`. */
35
+ export function exportedGcode(
36
+ result: { gcode: string; stats?: { colors?: (string | null)[]; filament_mm_by_tool?: number[] } },
37
+ sessionColors?: string[] | null,
38
+ ): string
39
+
40
+ /** Appends `; filament_colour = …` unless the text already states a palette. */
41
+ export function withFilamentColours(gcode: string, colors: (string | null | undefined)[]): string
42
+
17
43
  export interface ParseGcodeOptions {
18
44
  /** Used to derive bead width from E when the file has no ;WIDTH: comments. Default 1.75. */
19
45
  filamentDiameter?: number
@@ -147,6 +147,18 @@ export function readPresetFile(raw: Record<string, unknown> | null | undefined,
147
147
  /** The schema keys the kernel's machine limits are read from — for UI that shows which ones are in play. */
148
148
  export const machineLimitKeys: string[]
149
149
 
150
+ /** deriveKernelParams' fallbacks when neither the settings map nor the schema gives a usable value, keyed by schema
151
+ * key. NOT the schema defaults — several differ on purpose. Frozen. */
152
+ export const FFF_FALLBACKS: Readonly<Record<string, number | boolean | string>>
153
+ /** deriveSlaParams' fallbacks (its reader treats non-positive values as absent). Frozen. */
154
+ export const SLA_FALLBACKS: Readonly<Record<string, number>>
155
+ /** What `line_width` 0 ("auto") resolves to. */
156
+ export const AUTO_LINE_WIDTH: number
157
+ /** The bed when `printable_area` is empty or malformed — the bbox of the schema's own default. */
158
+ export const BED_FALLBACK: Readonly<{ width: number; depth: number }>
159
+ /** Kernel machine-limit parameter -> [schema key, fallback]. Frozen. */
160
+ export const MACHINE_LIMITS: Readonly<Record<string, readonly [string, number]>>
161
+
150
162
  export interface ProcessPresetsApi {
151
163
  /** Every key a process preset can set — clear these before applying a different one */
152
164
  keys: string[]
package/types/viewer.d.ts CHANGED
@@ -81,8 +81,10 @@ export interface ViewportProps {
81
81
  /**
82
82
  * G-code text to render instead of a slice result. Parsed into the same layer stream the kernel produces and
83
83
  * shown on the selected plate; the kernel is never started. While it is set, auto re-slice leaves that plate alone.
84
+ * A `{ plateIndex: text }` map puts each text on its own (0-based) plate, adding plates as needed — the shape an
85
+ * opened `.gcode.3mf` takes. This prop wins over a `.gcode.3mf` the user opens while it is set.
84
86
  */
85
- gcode?: string | null
87
+ gcode?: string | Record<number, string> | null
86
88
  /**
87
89
  * An `.sl1` archive rendered as a raster preview — the SLA half of {@link ViewportProps.gcode}'s contract: it
88
90
  * lands on the selected plate and the kernel is never started. Set both and the G-code wins; one plate holds
@@ -1,299 +0,0 @@
1
- import { unzip as Y, unzipSync as B } from "three/examples/jsm/libs/fflate.module.js";
2
- function W(t) {
3
- return new Promise((n) => {
4
- let o = !1;
5
- const e = (r) => {
6
- o || (o = !0, n(r));
7
- };
8
- try {
9
- Y(t, (r, i) => e(r ? B(t) : i));
10
- } catch {
11
- e(B(t));
12
- }
13
- });
14
- }
15
- const F = [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0];
16
- function q(t, n) {
17
- const o = new Array(12);
18
- for (let e = 0; e < 4; e++)
19
- for (let r = 0; r < 3; r++)
20
- o[e * 3 + r] = t[e * 3] * n[r] + t[e * 3 + 1] * n[3 + r] + t[e * 3 + 2] * n[6 + r] + (e === 3 ? n[9 + r] : 0);
21
- return o;
22
- }
23
- function C(t) {
24
- if (!t) return F;
25
- const n = t.trim().split(/\s+/).map(Number);
26
- return n.length === 12 && n.every(Number.isFinite) ? n : F;
27
- }
28
- const U = {};
29
- function p(t, n) {
30
- const e = (U[n] || (U[n] = new RegExp(`\\b${n}\\s*=\\s*"([^"]*)"`))).exec(t);
31
- return e ? e[1] : null;
32
- }
33
- const D = /<vertex\s+x="([^"]*)"\s+y="([^"]*)"\s+z="([^"]*)"/g, V = /<triangle\s+v1="([^"]*)"\s+v2="([^"]*)"\s+v3="([^"]*)"([^>]*)/g, $ = [
34
- ["paint_color", "color"],
35
- // multi-material: state 1..16 == Extruder1..16
36
- ["paint_supports", "supports"],
37
- // support enforcer/blocker: states 1 and 2
38
- ["paint_seam", "seam"],
39
- // unsupported by the kernel — collected for the warning only
40
- ["paint_fuzzy_skin", "fuzzy"]
41
- // ditto
42
- ];
43
- function G() {
44
- return { color: /* @__PURE__ */ new Map(), supports: /* @__PURE__ */ new Map(), seam: /* @__PURE__ */ new Map(), fuzzy: /* @__PURE__ */ new Map() };
45
- }
46
- function K(t) {
47
- return !t || $.every(([, n]) => t[n].size === 0);
48
- }
49
- function x(t, n, o) {
50
- for (const [e, r] of $) {
51
- if (!t.includes(e)) continue;
52
- const i = p(t, e);
53
- i && o[r].set(n, i);
54
- }
55
- }
56
- function Q(t) {
57
- const n = [];
58
- D.lastIndex = 0;
59
- let o;
60
- for (; o = D.exec(t); ) n.push(+o[1], +o[2], +o[3]);
61
- if (!n.length)
62
- for (const i of t.match(/<vertex\b[^>]*>/g) || []) n.push(+p(i, "x"), +p(i, "y"), +p(i, "z"));
63
- if (n.length < 9) return null;
64
- const e = [], r = G();
65
- for (V.lastIndex = 0; o = V.exec(t); ) {
66
- const i = e.length / 3;
67
- e.push(+o[1], +o[2], +o[3]), o[4].length > 2 && x(o[4], i, r);
68
- }
69
- if (!e.length)
70
- for (const i of t.match(/<triangle\b[^>]*>/g) || []) {
71
- const s = e.length / 3;
72
- e.push(+p(i, "v1"), +p(i, "v2"), +p(i, "v3")), x(i, s, r);
73
- }
74
- return e.length ? { verts: n, tris: e, paint: r } : null;
75
- }
76
- function Z(t) {
77
- const n = /* @__PURE__ */ new Map(), o = /<object\b([^>]*)>([\s\S]*?)<\/object>/g;
78
- let e;
79
- for (; e = o.exec(t); ) {
80
- const s = p(e[1], "id");
81
- if (!s) continue;
82
- const c = e[2], d = [];
83
- for (const f of c.match(/<component\b[^>]*>/g) || []) {
84
- const u = p(f, "objectid");
85
- u && d.push({ objectid: u, path: p(f, "p:path") || p(f, "path"), transform: C(p(f, "transform")) });
86
- }
87
- n.set(s, d.length ? { components: d } : { mesh: Q(c) });
88
- }
89
- const r = [], i = /<build\b[^>]*>([\s\S]*?)<\/build>/.exec(t);
90
- if (i)
91
- for (const s of i[1].match(/<item\b[^>]*>/g) || []) {
92
- const c = p(s, "objectid");
93
- c && r.push({ objectid: c, path: p(s, "p:path") || p(s, "path"), transform: C(p(s, "transform")) });
94
- }
95
- return { objects: n, items: r };
96
- }
97
- function O(t) {
98
- const n = String(t).replace(/^\/+/, "");
99
- return n.includes("%") ? decodeURIComponent(n) : n;
100
- }
101
- function k(t) {
102
- const n = {};
103
- for (const o of t.match(/<metadata\b[^>]*>/g) || []) {
104
- const e = p(o, "key");
105
- e && (n[e] = p(o, "value") ?? "");
106
- }
107
- return n;
108
- }
109
- function tt(t) {
110
- const n = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map(), e = /<object\b([^>]*)>([\s\S]*?)<\/object>/g;
111
- let r;
112
- for (; r = e.exec(t); ) {
113
- const c = p(r[1], "id");
114
- if (c) {
115
- const d = r[2];
116
- n.set(c, k(d.replace(/<(?:part|volume)\b[\s\S]*?<\/(?:part|volume)>/g, "")));
117
- const f = [];
118
- for (const u of d.match(/<volume\b[\s\S]*?<\/volume>/g) || []) {
119
- const _ = k(u).volume_type, y = _ === "SupportBlocker" ? "blocker" : _ === "SupportEnforcer" ? "enforcer" : null, j = Number(p(u, "firstid")), S = Number(p(u, "lastid"));
120
- y && Number.isInteger(j) && Number.isInteger(S) && j >= 0 && S >= j && f.push({ firstTriangle: j, lastTriangle: S, kind: y });
121
- }
122
- f.length && o.set(c, f);
123
- }
124
- }
125
- const i = [], s = /<plate\b[^>]*>([\s\S]*?)<\/plate>/g;
126
- for (; r = s.exec(t); ) {
127
- const c = r[1], d = k(c.replace(/<model_instance\b[\s\S]*?<\/model_instance>/g, "")), f = [];
128
- for (const u of c.match(/<model_instance\b[\s\S]*?<\/model_instance>/g) || []) {
129
- const _ = k(u).object_id;
130
- _ && f.push(_);
131
- }
132
- i.push({ index: Math.max(0, (Number(d.plater_id) || i.length + 1) - 1), objectIds: f });
133
- }
134
- return { objects: n, plates: i, volumes: o };
135
- }
136
- const et = Object.freeze({
137
- manualSupportPoints: "prepared-roundtrip",
138
- drainHoles: "preserved-unsupported",
139
- modifierVolumes: "prepared-mask-filtering",
140
- uiEditing: "unavailable"
141
- });
142
- function J(t, n, o, e, r) {
143
- const i = /* @__PURE__ */ new Map();
144
- if (!t?.trim()) return i;
145
- const s = t.trim().split(/\r?\n/), c = new RegExp(`^${n}_format_version=(\\d+)$`).exec(s[0]), d = c ? Number(c[1]) : 0;
146
- for (const f of s.slice(c ? 1 : 0)) {
147
- const u = /^object_id=(\d+)\|(.*)$/.exec(f);
148
- if (!u || i.has(Number(u?.[1]))) continue;
149
- const _ = Number(u[1]), y = u[2].trim() ? u[2].trim().split(/\s+/).map(Number) : [], j = o(d);
150
- if (!j || y.length % j !== 0 || y.some((a) => !Number.isFinite(a))) {
151
- e.push({ code: n === "support_points" ? "SLA_SUPPORT_POINT_COUNT" : "SLA_DRAIN_HOLE_COUNT", object: _ }), i.set(_, []);
152
- continue;
153
- }
154
- const S = [];
155
- for (let a = 0; a < y.length; a += j) S.push(r(y.slice(a, a + j), d));
156
- i.set(_, S);
157
- }
158
- return i;
159
- }
160
- function X(t, n) {
161
- const [o, e, r] = n;
162
- return [o * t[0] + e * t[3] + r * t[6] + t[9], o * t[1] + e * t[4] + r * t[7] + t[10], o * t[2] + e * t[5] + r * t[8] + t[11]];
163
- }
164
- function nt(t, n) {
165
- const [o, e, r] = n, i = [o * t[0] + e * t[3] + r * t[6], o * t[1] + e * t[4] + r * t[7], o * t[2] + e * t[5] + r * t[8]], s = Math.hypot(...i);
166
- return s ? i.map((c) => c / s) : i;
167
- }
168
- function ot(t, n) {
169
- const o = (s) => {
170
- const c = t.get(s);
171
- return c ? n.decode(c) : null;
172
- }, e = {
173
- settings: null,
174
- // Metadata/project_settings.config — the flattened preset (raw upstream strings)
175
- objectMeta: /* @__PURE__ */ new Map(),
176
- // 3mf object id -> per-object metadata (name, extruder, per-object overrides)
177
- plates: [],
178
- // [{index, objectIds}]
179
- hasLayerHeightProfile: !1,
180
- hasCustomGcodePerLayer: !1,
181
- volumeMeta: /* @__PURE__ */ new Map(),
182
- sla: { capabilities: { ...et }, issues: [], supportPoints: /* @__PURE__ */ new Map(), drainHoles: /* @__PURE__ */ new Map() }
183
- }, r = o("Metadata/project_settings.config");
184
- if (r)
185
- try {
186
- e.settings = JSON.parse(r);
187
- } catch {
188
- e.settings = null;
189
- }
190
- const i = o("Metadata/model_settings.config");
191
- if (i) {
192
- const s = tt(i);
193
- e.objectMeta = s.objects, e.plates = s.plates, e.volumeMeta = s.volumes;
194
- }
195
- return e.sla.supportPoints = J(
196
- o("Metadata/Slic3r_PE_sla_support_points.txt"),
197
- "support_points",
198
- (s) => s === 0 ? 3 : s === 1 ? 5 : 0,
199
- e.sla.issues,
200
- (s, c) => ({
201
- position: s.slice(0, 3),
202
- radius: c === 0 ? 0.4 : s[3],
203
- type: c === 0 || s[4] === 2 ? "manual" : s[4] === 1 ? "island" : "slope"
204
- })
205
- ), e.sla.drainHoles = J(
206
- o("Metadata/Slic3r_PE_sla_drain_holes.txt"),
207
- "drain_holes",
208
- (s) => s === 1 ? 8 : 0,
209
- e.sla.issues,
210
- (s) => {
211
- const c = Math.hypot(s[3], s[4], s[5]), d = c ? s.slice(3, 6).map((f) => f / c) : s.slice(3, 6);
212
- return { position: s.slice(0, 3).map((f, u) => f + d[u]), normal: d, radius: s[6], height: s[7] - 1 };
213
- }
214
- ), e.hasLayerHeightProfile = !!o("Metadata/layer_heights_profile.txt")?.trim(), e.hasCustomGcodePerLayer = !!o("Metadata/custom_gcode_per_layer.xml")?.trim(), e;
215
- }
216
- async function rt(t, n = "model") {
217
- const o = ArrayBuffer.isView(t) ? new Uint8Array(t.buffer, t.byteOffset, t.byteLength) : new Uint8Array(t), e = await W(o), r = /* @__PURE__ */ new Map();
218
- for (const a of Object.keys(e)) r.set(O(a), e[a]);
219
- const i = new TextDecoder(), s = /* @__PURE__ */ new Map(), c = (a) => {
220
- const w = O(a);
221
- if (s.has(w)) return s.get(w);
222
- const l = r.get(w), M = l ? Z(i.decode(l)) : null;
223
- return s.set(w, M), M;
224
- };
225
- let d = "3D/3dmodel.model";
226
- const f = r.get("_rels/.rels");
227
- if (f) {
228
- for (const a of i.decode(f).match(/<Relationship\b[^>]*>/g) || [])
229
- if ((p(a, "Type") || "").endsWith("/3dmodel")) {
230
- d = O(p(a, "Target"));
231
- break;
232
- }
233
- }
234
- const u = c(d);
235
- if (!u) throw new Error(`3MF root model not found: ${d}`);
236
- const _ = [], y = ot(r, i), j = (a, w, l, M, P, N) => {
237
- if (N > 16) return;
238
- const T = c(w)?.objects.get(a);
239
- if (!T) return;
240
- if (T.components) {
241
- for (const b of T.components) j(b.objectid, b.path || w, q(b.transform, l), M, P, N + 1);
242
- return;
243
- }
244
- if (!T.mesh) return;
245
- const { verts: z, tris: I, paint: v } = T.mesh, E = M.length / 9;
246
- for (let b = 0; b < I.length; b++) {
247
- const m = I[b] * 3, g = z[m], h = z[m + 1], A = z[m + 2];
248
- M.push(
249
- g * l[0] + h * l[3] + A * l[6] + l[9],
250
- g * l[1] + h * l[4] + A * l[7] + l[10],
251
- g * l[2] + h * l[5] + A * l[8] + l[11]
252
- );
253
- }
254
- if (v) for (const [, b] of $)
255
- for (const [m, g] of v[b]) P[b].set(E + m, g);
256
- }, S = u.items.length ? u.items : [...u.objects.keys()].filter((a) => u.objects.get(a).mesh).map((a) => ({ objectid: a, path: d, transform: F }));
257
- return S.forEach((a, w) => {
258
- const l = [], M = G();
259
- if (j(a.objectid, a.path || d, a.transform, l, M, 0), l.length < 9) return;
260
- let P = new Float32Array(l);
261
- const N = [], R = y.volumeMeta.get(a.objectid) || [];
262
- if (R.length) {
263
- const m = /* @__PURE__ */ new Set();
264
- for (let g = 0; g < R.length; g++) {
265
- const h = R[g], A = h.firstTriangle * 9, H = Math.min(l.length, (h.lastTriangle + 1) * 9);
266
- if (!(A >= H)) {
267
- for (let L = h.firstTriangle; L <= h.lastTriangle; L++) m.add(L);
268
- N.push({ id: `${a.objectid}:modifier:${g}`, kind: h.kind, tris: new Float32Array(l.slice(A, H)) });
269
- }
270
- }
271
- if (m.size) {
272
- const g = [];
273
- for (let h = 0; h < l.length / 9; h++) m.has(h) || g.push(...l.slice(h * 9, h * 9 + 9));
274
- P = new Float32Array(g);
275
- }
276
- }
277
- const T = (y.sla.supportPoints.get(w + 1) || []).map((m) => ({ ...m, position: X(a.transform, m.position) })), z = (y.sla.drainHoles.get(w + 1) || []).map((m) => ({
278
- ...m,
279
- position: X(a.transform, m.position),
280
- normal: nt(a.transform, m.normal)
281
- }));
282
- let I = 1 / 0, v = 1 / 0, E = -1 / 0, b = -1 / 0;
283
- for (let m = 0; m < P.length; m += 3) {
284
- const g = P[m], h = P[m + 1];
285
- g < I && (I = g), g > E && (E = g), h < v && (v = h), h > b && (b = h);
286
- }
287
- _.push({
288
- name: S.length > 1 ? `${n}#${w + 1}` : n,
289
- tris: P,
290
- objectid: a.objectid,
291
- paint: K(M) ? null : M,
292
- sla: { supportPoints: T, drainHoles: z, modifierVolumes: N },
293
- bbox: { minX: I, minY: v, maxX: E, maxY: b }
294
- });
295
- }), { objects: _, project: y };
296
- }
297
- export {
298
- rt as p
299
- };
@@ -1,176 +0,0 @@
1
- const U = new Int8Array(8), W = new Int8Array(8), G = new Int8Array(8);
2
- for (let t = 0; t < 8; t++)
3
- U[t] = t & 1, W[t] = t >> 1 & 1, G[t] = t >> 2 & 1;
4
- const T = [], rt = [];
5
- for (let t = 0; t < 8; t++) for (let l = t + 1; l < 8; l++)
6
- Math.abs(U[t] - U[l]) + Math.abs(W[t] - W[l]) + Math.abs(G[t] - G[l]) === 1 && (T.push(t), rt.push(l));
7
- const ot = 127.5, q = (t) => t > ot, x = (t) => {
8
- const l = [];
9
- let A = new t(1048576), r = 0, m = 0;
10
- return {
11
- push3(u, C, h) {
12
- r + 3 > A.length && (l.push(A.subarray(0, r)), m += r, A = new t(1 << 20), r = 0), A[r++] = u, A[r++] = C, A[r++] = h;
13
- },
14
- concat() {
15
- l.push(A.subarray(0, r)), m += r;
16
- const u = new t(m);
17
- let C = 0;
18
- for (const h of l)
19
- u.set(h, C), C += h.length;
20
- return u;
21
- }
22
- };
23
- }, ct = { 0: [0.68, 0.238, 0.023], 5: [0.328, 0.188, 0.687], 6: [0.434, 0.352, 0.144] };
24
- function ht(t, l, A, r, m, u, C, h) {
25
- const b = t + 1, a = l + 1;
26
- let o = new Int32Array(b * a).fill(-1), i = new Int32Array(b * a).fill(-1);
27
- const N = null;
28
- let F = N, w = N, H = null, P = null, J = null, d = null, at = 0;
29
- const tt = x(Float32Array), Y = x(Uint32Array), et = x(Float32Array);
30
- let nt = 0, Q = !1;
31
- const S = (g, c, n) => !g || c < 0 || n < 0 || c >= t || n >= l ? 0 : g[c + t * n], O = new Float64Array(8);
32
- function lt(g, c, n, R, s, k, y, p) {
33
- const e = c + 1 + b * (n + 1), M = g[e];
34
- if (M >= 0) return M;
35
- O[0] = S(s, c, n), O[1] = S(s, c + 1, n), O[2] = S(s, c, n + 1), O[3] = S(s, c + 1, n + 1), O[4] = S(k, c, n), O[5] = S(k, c + 1, n), O[6] = S(k, c, n + 1), O[7] = S(k, c + 1, n + 1);
36
- let z = 0, f = 0, I = 0, v = 0;
37
- for (let E = 0; E < T.length; E++) {
38
- const B = T[E], L = rt[E];
39
- if (q(O[B]) === q(O[L])) continue;
40
- const X = Math.min(1, Math.max(0, (ot - O[B]) / (O[L] - O[B])));
41
- z += U[B] + X * (U[L] - U[B]), f += W[B] + X * (W[L] - W[B]), I += G[B] + X * (G[L] - G[B]), v++;
42
- }
43
- const K = v ? z / v : 0.5, j = v ? f / v : 0.5, D = v ? I / v : 0.5;
44
- if (tt.push3(u + (c + K + 0.5) * A, C + (n + j + 0.5) * r, h + (R + D + 0.5) * m), Q) {
45
- let E = 0;
46
- for (let L = 0; L < 8; L++) {
47
- if (!q(O[L])) continue;
48
- const X = S(G[L] ? p : y, c + U[L], n + W[L]);
49
- if (X === 5) {
50
- E = 5;
51
- break;
52
- }
53
- X === 6 && (E = 6);
54
- }
55
- const B = ct[E];
56
- et.push3(B[0], B[1], B[2]);
57
- }
58
- return g[e] = nt, nt++;
59
- }
60
- const Z = (g, c, n) => c === N || n < 0 || n >= l ? t : g ? g[n * 2] : 0, _ = (g, c, n) => c === N || n < 0 || n >= l ? -1 : g ? g[n * 2 + 1] : t - 1;
61
- function V(g, c, n) {
62
- const R = at++, s = (e, M) => lt(o, e, M, R - 1, F, w, H, P), k = (e, M) => lt(i, e, M, R, w, g, P, c), y = (e, M, z, f, I) => {
63
- I ? (Y.push3(f, z, M), Y.push3(f, M, e)) : (Y.push3(e, M, z), Y.push3(e, z, f));
64
- };
65
- for (let e = 0; e < l; e++) {
66
- const M = Math.min(Z(J, F, e), Z(d, w, e)), z = Math.max(_(J, F, e), _(d, w, e));
67
- for (let f = M; f <= z; f++) {
68
- const I = q(S(F, f, e)), v = q(S(w, f, e));
69
- I !== v && y(s(f - 1, e - 1), s(f, e - 1), s(f, e), s(f - 1, e), !I);
70
- }
71
- }
72
- for (let e = 0; e < l; e++) {
73
- const M = Z(d, w, e), z = _(d, w, e);
74
- for (let f = M - 1; f <= z; f++) {
75
- const I = q(S(w, f, e)), v = q(S(w, f + 1, e));
76
- I !== v && y(s(f, e - 1), s(f, e), k(f, e), k(f, e - 1), !I);
77
- }
78
- }
79
- for (let e = -1; e < l; e++) {
80
- const M = Math.min(Z(d, w, e), Z(d, w, e + 1)), z = Math.max(_(d, w, e), _(d, w, e + 1));
81
- for (let f = M; f <= z; f++) {
82
- const I = q(S(w, f, e)), v = q(S(w, f, e + 1));
83
- I !== v && y(s(f - 1, e), k(f - 1, e), k(f, e), s(f, e), !I);
84
- }
85
- }
86
- const p = o;
87
- o = i, i = p.fill(-1);
88
- }
89
- let $ = !1;
90
- return {
91
- // Slices arrive bottom-up. Layer s can only be processed once s+1 is known (its cells' upper corners live
92
- // there), so the first slice just primes the window and every later push runs the step one layer behind.
93
- // `roles` is an optional parallel Uint8Array (0=model, 5=support, 6=pad) that turns on vertex colours;
94
- // `ranges` the per-row occupancy spans fillSliceFromRGBA returns, which confine the sweep to the model.
95
- pushSlice(g, c = null, n = null) {
96
- if (c && (Q = !0), !$) {
97
- $ = !0, w = g, P = c, d = n;
98
- return;
99
- }
100
- V(g, c), F = w, w = g, H = P, P = c, J = d, d = n;
101
- },
102
- finish({ smoothRounds: g = 0, normalRounds: c = 0 } = {}) {
103
- $ && (V(N, null), F = w, w = N, H = P, P = null, J = d, d = null), V(N, null);
104
- const n = tt.concat(), R = Y.concat();
105
- g > 0 && st(n, R, g);
106
- const s = new Float32Array(n.length);
107
- for (let k = 0; k < R.length; k += 3) {
108
- const y = R[k] * 3, p = R[k + 1] * 3, e = R[k + 2] * 3, M = n[p] - n[y], z = n[p + 1] - n[y + 1], f = n[p + 2] - n[y + 2], I = n[e] - n[y], v = n[e + 1] - n[y + 1], K = n[e + 2] - n[y + 2], j = z * K - f * v, D = f * I - M * K, E = M * v - z * I;
109
- s[y] += j, s[y + 1] += D, s[y + 2] += E, s[p] += j, s[p + 1] += D, s[p + 2] += E, s[e] += j, s[e + 1] += D, s[e + 2] += E;
110
- }
111
- return ft(s), c > 0 && ut(s, R, c), { positions: n, indices: R, normals: s, colors: Q ? et.concat() : null };
112
- }
113
- };
114
- }
115
- function ft(t) {
116
- for (let l = 0; l < t.length; l += 3) {
117
- const A = Math.hypot(t[l], t[l + 1], t[l + 2]) || 1;
118
- t[l] /= A, t[l + 1] /= A, t[l + 2] /= A;
119
- }
120
- }
121
- function ut(t, l, A = 2) {
122
- const r = new Float32Array(t.length);
123
- for (let m = 0; m < A; m++) {
124
- r.fill(0);
125
- for (let u = 0; u < l.length; u += 3) {
126
- const C = l[u] * 3, h = l[u + 1] * 3, b = l[u + 2] * 3;
127
- for (const [a, o] of [[C, h], [h, b], [b, C]])
128
- r[a] += t[o], r[a + 1] += t[o + 1], r[a + 2] += t[o + 2], r[o] += t[a], r[o + 1] += t[a + 1], r[o + 2] += t[a + 2];
129
- }
130
- for (let u = 0; u < t.length; u += 3)
131
- t[u] += 0.5 * r[u], t[u + 1] += 0.5 * r[u + 1], t[u + 2] += 0.5 * r[u + 2];
132
- ft(t);
133
- }
134
- }
135
- function st(t, l, A = 4) {
136
- const r = new Float32Array(t.length), m = new Float32Array(t.length / 3), u = (h, b) => {
137
- const a = h * 3, o = b * 3, i = Math.abs(t[o + 2] - t[a + 2]) + 0.05 * (Math.abs(t[o] - t[a]) + Math.abs(t[o + 1] - t[a + 1])) + 1e-6;
138
- r[a] += i * t[o], r[a + 1] += i * t[o + 1], r[a + 2] += i * t[o + 2], r[o] += i * t[a], r[o + 1] += i * t[a + 1], r[o + 2] += i * t[a + 2], m[h] += i, m[b] += i;
139
- }, C = (h) => {
140
- r.fill(0), m.fill(0);
141
- for (let b = 0; b < l.length; b += 3) {
142
- const a = l[b], o = l[b + 1], i = l[b + 2];
143
- u(a, o), u(o, i), u(i, a);
144
- }
145
- for (let b = 0; b < m.length; b++) {
146
- const a = m[b];
147
- if (!a) continue;
148
- const o = b * 3;
149
- t[o] += h * (r[o] / a - t[o]), t[o + 1] += h * (r[o + 1] / a - t[o + 1]), t[o + 2] += h * (r[o + 2] / a - t[o + 2]);
150
- }
151
- };
152
- for (let h = 0; h < A; h++)
153
- C(0.5), C(-0.53);
154
- }
155
- function bt(t, l, A, r, m) {
156
- const u = new Uint32Array(l.buffer, l.byteOffset, l.byteLength >> 2), C = new Int32Array(r * 2);
157
- for (let h = 0; h < r; h++) {
158
- const b = r - 1 - h, a = h * A * 4 >> 2, o = A * (b + r * m);
159
- let i = A, N = -1;
160
- for (let F = 0; F < A; F++) {
161
- const w = u[a + F];
162
- if (w === 0) {
163
- t[o + F] = 0;
164
- continue;
165
- }
166
- const H = w >> 8 & 255;
167
- t[o + F] = H, H && (F < i && (i = F), F > N && (N = F));
168
- }
169
- C[b * 2] = i, C[b * 2 + 1] = N;
170
- }
171
- return C;
172
- }
173
- export {
174
- bt as f,
175
- ht as m
176
- };