three-slicer-viewer 0.3.2 → 0.3.4
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/TOOLPATH_SPEC.md +8 -1
- package/VIEWER.md +24 -0
- package/data/config-schema-lean.json +1 -1
- package/dist/components.js +47 -43
- package/dist/gcode_parse.js +154 -111
- package/dist/index.js +4409 -4069
- package/dist/{model_loaders-DxlFNFOu.js → model_loaders-Dk9rqXFb.js} +27 -27
- package/dist/model_loaders.js +2 -2
- package/dist/parse_3mf-CpbA-6Iq.js +666 -0
- package/dist/parse_3mf.worker.js +67 -5
- package/dist/sl1_encode.worker.js +1 -1
- package/dist/sl1_write-B6nWmCUu.js +313 -0
- package/dist/sla_slice.worker.js +1 -1
- package/dist/toolpath.js +303 -177
- package/package.json +6 -1
- package/src/core/paint_tools.js +8 -0
- package/src/settings/bed_frame.js +28 -0
- package/src/settings/index.js +1 -0
- package/src/settings/kernel_setting_keys.js +79 -0
- package/src/settings/settings_core.js +194 -8
- package/types/gcode.d.ts +13 -0
- package/types/paint.d.ts +7 -0
- package/types/settings.d.ts +14 -1
- package/types/toolpath.d.ts +6 -0
- package/types/viewer.d.ts +1 -1
- package/dist/parse_3mf-BZISF3eW.js +0 -327
- package/dist/sl1_write-BovHbg3k.js +0 -303
package/dist/components.js
CHANGED
|
@@ -8,39 +8,39 @@ import { S as X } from "./shadow_host-CQ3LirzD.js";
|
|
|
8
8
|
const Y = ':host{display:contents}*{box-sizing:border-box}.row{display:grid;grid-template-columns:260px 220px 70px 1fr;gap:8px;align-items:center;padding:3px 0;border-bottom:1px dashed var(--_light-divider)}.row .lbl{color:var(--_light-text);text-decoration:none}.row .lbl:hover{color:var(--_accent-ink);text-decoration:underline}.row .key{font-size:11px;color:var(--_light-text-faint);overflow:hidden;text-overflow:ellipsis}.row input[type=text],.row input:not([type]),.row select,.row textarea{width:100%;max-width:260px;padding:2px 6px}.inputwrap{display:inline-flex;align-items:center;gap:4px}.unit{color:var(--_light-text-faint);font-size:12px;white-space:nowrap}.pts{font-size:11px;color:var(--_light-text-muted)}.badge{font-size:10px;padding:1px 6px;border-radius:8px;color:var(--_on-accent);text-align:center}.mode-simple{background:var(--_accent-ink)}.mode-advanced{background:var(--_info-ink)}.mode-expert{background:var(--_warn)}.mode-develop{background:var(--_danger)}.mode-none,.mode-undefined{background:var(--_light-text-faint)}.muted{color:var(--_light-text-faint);font-weight:400;font-size:12px}.row.custom{grid-template-columns:1fr}.row.disabled{opacity:.42}.row.disabled input,.row.disabled select,.row.disabled textarea{cursor:not-allowed;background:var(--_light-subtle)}.lbl-cell{display:inline-flex;align-items:center;gap:5px;min-width:0}.lbl-cell .lbl{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dirty-dot{flex:0 0 auto;width:7px;height:7px;border-radius:50%;background:var(--_warn);box-shadow:0 0 0 2px var(--_warn-soft)}.override-dot{flex:0 0 auto;width:9px;height:9px;border-radius:50%;background:var(--_warn);border:0;padding:0;cursor:pointer;box-shadow:0 0 0 2px var(--_warn-soft)}.override-dot:hover{background:var(--_warn-ink)}.widget-cell{display:inline-flex;align-items:center;gap:6px;min-width:0}.reset-btn{flex:0 0 auto;border:1px solid var(--_warn-border);background:var(--_warn-soft);color:var(--_warn-ink);border-radius:5px;cursor:pointer;font-size:13px;line-height:1;padding:1px 5px}.reset-btn:hover{background:var(--_warn-soft-hover)}.settings-panel{flex:0 0 400px;width:400px;border-left:1px solid var(--_light-divider);display:flex;flex-direction:column;min-height:0;background:var(--_light-surface);color:var(--_light-text);font:14px/1.5 -apple-system,Segoe UI,sans-serif}.settings-panel .sp-top{padding:10px 12px 8px;border-bottom:1px solid var(--_light-divider)}.sp-builder{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--_light-text-muted)}.sp-builder select{flex:1;padding:4px 6px}.sp-pages{display:flex;flex-wrap:wrap;gap:4px;margin-top:8px}.sp-pages button{border:1px solid var(--_light-border);background:var(--_light-subtle);border-radius:6px;padding:4px 8px;font-size:12px;cursor:pointer}.sp-pages button.on{background:var(--_accent-soft);color:var(--_accent-ink);border-color:var(--_accent-soft-border);font-weight:700}.sp-modes{display:flex;gap:4px;margin-top:8px}.sp-modes button{border:0;background:none;font-size:11px;color:var(--_light-text-faint);padding:2px 6px;border-radius:6px;cursor:pointer}.sp-modes button.on{background:var(--_accent-soft);color:var(--_accent-ink);font-weight:700}.settings-panel .sp-body{flex:1 1 auto;overflow-y:auto;padding:8px 14px 24px}.settings-panel .sp-body h2{font-size:16px}.settings-panel .row{grid-template-columns:1fr auto;grid-template-areas:"lbl badge" "key widget";row-gap:2px;padding:6px 0}.settings-panel .row .lbl{grid-area:lbl;font-weight:600}.settings-panel .row .badge{grid-area:badge;justify-self:end}.settings-panel .row .key{grid-area:key}.settings-panel .row .inputwrap,.settings-panel .row>select,.settings-panel .row>input,.settings-panel .row>textarea,.settings-panel .row>.pts,.settings-panel .row>.muted{grid-area:widget;justify-self:end}.settings-panel .row input:not([type=checkbox]):not([type=color]),.settings-panel .row select,.settings-panel .row textarea{max-width:200px}.settings-panel .row.custom{grid-template-columns:1fr;grid-template-areas:"lbl"}.sp-search{width:100%;box-sizing:border-box;padding:6px 9px;border:1px solid var(--_light-border);border-radius:6px;font-size:13px;margin-bottom:8px}:host(.sp-embedded) .settings-panel{position:static;width:auto;flex:none;border:0;height:auto}:host(.sp-embedded) .sp-body{padding:4px 2px 8px;max-height:460px}.bse{display:flex;flex-direction:column;gap:6px;min-width:0;max-width:220px}.bse-modes{display:flex;gap:4px}.bse-modes button{border:1px solid var(--_light-border);background:var(--_light-subtle);border-radius:6px;padding:2px 8px;font-size:11px;cursor:pointer}.bse-modes button.on{background:var(--_accent-soft);color:var(--_accent-ink);border-color:var(--_accent-soft-border);font-weight:700}.bse-grid{display:grid;grid-template-columns:1fr 1fr;gap:4px 8px}.bse-grid label{display:flex;align-items:center;gap:4px;font-size:11px;color:var(--_light-text-muted);white-space:nowrap}.bse-grid input{width:56px;padding:2px 4px;font-size:12px}.bse-json{width:100%;font:11px ui-monospace,monospace;padding:4px 6px;border:1px solid var(--_light-border);border-radius:6px;box-sizing:border-box}.bse-json.err{border-color:var(--_danger);background:var(--_danger-soft)}', q = (t, a, r, o) => [[r, o], [t + r, o], [t + r, a + o], [r, a + o]], L = R.printable_area.default, V = (t) => {
|
|
9
9
|
const a = t / 2, r = 32;
|
|
10
10
|
return Array.from({ length: r }, (o, i) => {
|
|
11
|
-
const
|
|
12
|
-
return [+(a + a * Math.cos(
|
|
11
|
+
const m = 2 * Math.PI * i / r;
|
|
12
|
+
return [+(a + a * Math.cos(m)).toFixed(2), +(a + a * Math.sin(m)).toFixed(2)];
|
|
13
13
|
});
|
|
14
14
|
}, T = (t) => {
|
|
15
15
|
const a = t.map((o) => o[0]), r = t.map((o) => o[1]);
|
|
16
16
|
return { x0: Math.min(...a), y0: Math.min(...r), w: Math.max(...a) - Math.min(...a), d: Math.max(...r) - Math.min(...r) };
|
|
17
17
|
};
|
|
18
18
|
function Z({ value: t, onChange: a, disabled: r }) {
|
|
19
|
-
const o = Array.isArray(t) && t.length >= 3 ? t : L, i = T(o), [
|
|
19
|
+
const o = Array.isArray(t) && t.length >= 3 ? t : L, i = T(o), [m, d] = y(o.length === 4 ? "rect" : o.length >= 12 ? "circle" : "custom"), [c, p] = y({ w: i.w, d: i.d, ox: i.x0, oy: i.y0 }), [x, b] = y(Math.round(i.w)), [l, u] = y(JSON.stringify(o)), [_, w] = y(!1);
|
|
20
20
|
P(() => {
|
|
21
21
|
const n = T(o);
|
|
22
|
-
p({ w: n.w, d: n.d, ox: n.x0, oy: n.y0 }),
|
|
22
|
+
p({ w: n.w, d: n.d, ox: n.x0, oy: n.y0 }), b(Math.round(n.w)), u(JSON.stringify(o)), w(!1);
|
|
23
23
|
}, [JSON.stringify(t)]);
|
|
24
24
|
const v = (n) => {
|
|
25
25
|
p(n);
|
|
26
|
-
const { w:
|
|
27
|
-
|
|
28
|
-
},
|
|
29
|
-
|
|
26
|
+
const { w: g, d: f, ox: S, oy: M } = n;
|
|
27
|
+
g > 0 && f > 0 && a(q(g, f, S, M));
|
|
28
|
+
}, N = (n) => {
|
|
29
|
+
b(n), n > 0 && a(V(n));
|
|
30
30
|
}, z = (n) => {
|
|
31
|
-
|
|
31
|
+
u(n);
|
|
32
32
|
try {
|
|
33
|
-
const
|
|
34
|
-
if (!Array.isArray(
|
|
35
|
-
w(!1), a(
|
|
33
|
+
const g = JSON.parse(n);
|
|
34
|
+
if (!Array.isArray(g) || g.length < 3 || !g.every((f) => Array.isArray(f) && f.length === 2 && f.every(Number.isFinite))) throw 0;
|
|
35
|
+
w(!1), a(g);
|
|
36
36
|
} catch {
|
|
37
37
|
w(!0);
|
|
38
38
|
}
|
|
39
39
|
}, E = (n) => {
|
|
40
|
-
const
|
|
41
|
-
return Number.isFinite(
|
|
40
|
+
const g = parseFloat(n);
|
|
41
|
+
return Number.isFinite(g) ? g : 0;
|
|
42
42
|
};
|
|
43
|
-
return /* @__PURE__ */ e.createElement("div", { className: "bse", "data-testid": "bed-shape-editor" }, /* @__PURE__ */ e.createElement("div", { className: "bse-modes" }, [["rect", "Rectangular"], ["circle", "Circular"], ["custom", "Custom"]].map(([n,
|
|
43
|
+
return /* @__PURE__ */ e.createElement("div", { className: "bse", "data-testid": "bed-shape-editor" }, /* @__PURE__ */ e.createElement("div", { className: "bse-modes" }, [["rect", "Rectangular"], ["circle", "Circular"], ["custom", "Custom"]].map(([n, g]) => /* @__PURE__ */ e.createElement("button", { key: n, type: "button", className: m === n ? "on" : "", disabled: r, onClick: () => d(n) }, g))), m === "rect" && /* @__PURE__ */ e.createElement("div", { className: "bse-grid" }, /* @__PURE__ */ e.createElement("label", null, "Width ", /* @__PURE__ */ e.createElement(
|
|
44
44
|
"input",
|
|
45
45
|
{
|
|
46
46
|
type: "number",
|
|
@@ -76,7 +76,7 @@ function Z({ value: t, onChange: a, disabled: r }) {
|
|
|
76
76
|
disabled: r,
|
|
77
77
|
onChange: (n) => v({ ...c, oy: E(n.target.value) })
|
|
78
78
|
}
|
|
79
|
-
))),
|
|
79
|
+
))), m === "circle" && /* @__PURE__ */ e.createElement("div", { className: "bse-grid" }, /* @__PURE__ */ e.createElement("label", null, "Diameter ", /* @__PURE__ */ e.createElement(
|
|
80
80
|
"input",
|
|
81
81
|
{
|
|
82
82
|
type: "number",
|
|
@@ -84,12 +84,12 @@ function Z({ value: t, onChange: a, disabled: r }) {
|
|
|
84
84
|
value: x,
|
|
85
85
|
disabled: r,
|
|
86
86
|
"data-testid": "bed-dia",
|
|
87
|
-
onChange: (n) =>
|
|
87
|
+
onChange: (n) => N(E(n.target.value))
|
|
88
88
|
}
|
|
89
|
-
), " mm")),
|
|
89
|
+
), " mm")), m === "custom" && /* @__PURE__ */ e.createElement(
|
|
90
90
|
"textarea",
|
|
91
91
|
{
|
|
92
|
-
className: "bse-json" + (
|
|
92
|
+
className: "bse-json" + (_ ? " err" : ""),
|
|
93
93
|
rows: 3,
|
|
94
94
|
value: l,
|
|
95
95
|
disabled: r,
|
|
@@ -118,35 +118,39 @@ function le(t) {
|
|
|
118
118
|
function ie({ mode: t }) {
|
|
119
119
|
return /* @__PURE__ */ e.createElement("span", { className: `badge mode-${t ?? "none"}` }, t ?? "—");
|
|
120
120
|
}
|
|
121
|
-
function ce({ def: t, optKey: a, settings: r, setSettings: o, disabled: i, customWidgets:
|
|
122
|
-
const d = I(r, a), c = (l) => o((
|
|
121
|
+
function ce({ def: t, optKey: a, settings: r, setSettings: o, disabled: i, customWidgets: m }) {
|
|
122
|
+
const d = I(r, a), c = (l) => o((u) => ({ ...u, [a]: l })), p = m?.[a] ?? K[a];
|
|
123
123
|
if (p) return /* @__PURE__ */ e.createElement(p, { def: t, value: d, onChange: c, disabled: i });
|
|
124
|
-
const x = le(t),
|
|
124
|
+
const x = le(t), b = Array.isArray(d) ? d[0] : d;
|
|
125
125
|
switch (x) {
|
|
126
126
|
case "select":
|
|
127
|
-
return /* @__PURE__ */ e.createElement("select", { value:
|
|
127
|
+
return /* @__PURE__ */ e.createElement("select", { value: b ?? "", onChange: (l) => c(l.target.value), disabled: i }, t.enum_values.map((l, u) => /* @__PURE__ */ e.createElement("option", { key: l, value: l }, t.enum_labels?.[u] ?? l)));
|
|
128
128
|
case "checkbox":
|
|
129
129
|
return /* @__PURE__ */ e.createElement("input", { type: "checkbox", checked: Array.isArray(d) ? !!d[0] : !!d, onChange: (l) => c(l.target.checked), disabled: i });
|
|
130
130
|
case "color":
|
|
131
|
-
return /* @__PURE__ */ e.createElement("input", { type: "color", value: typeof
|
|
132
|
-
case "textarea":
|
|
133
|
-
|
|
134
|
-
|
|
131
|
+
return /* @__PURE__ */ e.createElement("input", { type: "color", value: typeof b == "string" && b.startsWith("#") ? b : H, onChange: (l) => c(l.target.value), disabled: i });
|
|
132
|
+
case "textarea": {
|
|
133
|
+
let l = 2;
|
|
134
|
+
t.full_width && (l = 12);
|
|
135
|
+
let u = d ?? "";
|
|
136
|
+
return Array.isArray(d) && (u = d.join(`
|
|
137
|
+
`)), /* @__PURE__ */ e.createElement("textarea", { rows: l, value: u, onChange: (_) => c(_.target.value), disabled: i });
|
|
138
|
+
}
|
|
135
139
|
case "points":
|
|
136
140
|
return /* @__PURE__ */ e.createElement("code", { className: "pts" }, JSON.stringify(d ?? []));
|
|
137
141
|
case "unknown":
|
|
138
142
|
return /* @__PURE__ */ e.createElement("span", { className: "muted" }, "No schema");
|
|
139
143
|
default:
|
|
140
|
-
return /* @__PURE__ */ e.createElement("span", { className: "inputwrap" }, /* @__PURE__ */ e.createElement("input", { value:
|
|
144
|
+
return /* @__PURE__ */ e.createElement("span", { className: "inputwrap" }, /* @__PURE__ */ e.createElement("input", { value: b ?? "", onChange: (l) => c(l.target.value), disabled: i }), t.sidetext && /* @__PURE__ */ e.createElement("span", { className: "unit" }, t.sidetext));
|
|
141
145
|
}
|
|
142
146
|
}
|
|
143
|
-
function de({ schema: t, optKey: a, settings: r, setSettings: o, disabled: i, onOptionOpen:
|
|
147
|
+
function de({ schema: t, optKey: a, settings: r, setSettings: o, disabled: i, onOptionOpen: m, customWidgets: d, overridden: c, onRevertKey: p }) {
|
|
144
148
|
if (a.startsWith("<")) return /* @__PURE__ */ e.createElement("div", { className: "row custom" }, /* @__PURE__ */ e.createElement("span", { className: "muted" }, "⚙ Custom widget ", a));
|
|
145
|
-
const x = t[a],
|
|
146
|
-
const
|
|
147
|
-
return delete
|
|
149
|
+
const x = t[a], b = i ? i[a] : void 0, l = b != null, u = oe(t, r, a), _ = () => o((v) => {
|
|
150
|
+
const N = { ...v };
|
|
151
|
+
return delete N[a], N;
|
|
148
152
|
}), w = x?.label || x?.full_label || a;
|
|
149
|
-
return /* @__PURE__ */ e.createElement("div", { className: "row" + (l ? " disabled" : ""), title: l ? `Disabled when: ${
|
|
153
|
+
return /* @__PURE__ */ e.createElement("div", { className: "row" + (l ? " disabled" : ""), title: l ? `Disabled when: ${b}` : x?.tooltip ?? "", "data-testid": `row-${a}` }, /* @__PURE__ */ e.createElement("span", { className: "lbl-cell" }, c && /* @__PURE__ */ e.createElement(
|
|
150
154
|
"button",
|
|
151
155
|
{
|
|
152
156
|
type: "button",
|
|
@@ -155,7 +159,7 @@ function de({ schema: t, optKey: a, settings: r, setSettings: o, disabled: i, on
|
|
|
155
159
|
title: "This plate's override — click to follow the global value again",
|
|
156
160
|
"data-testid": `override-${a}`
|
|
157
161
|
}
|
|
158
|
-
),
|
|
162
|
+
), u && /* @__PURE__ */ e.createElement("span", { className: "dirty-dot", title: "Changed from default", "data-testid": `dirty-${a}` }), m ? /* @__PURE__ */ e.createElement("button", { type: "button", className: "lbl lbl-link", onClick: () => m(a), title: "Details" }, w) : /* @__PURE__ */ e.createElement("span", { className: "lbl" }, w)), /* @__PURE__ */ e.createElement("code", { className: "key" }, a), /* @__PURE__ */ e.createElement(ie, { mode: x?.mode }), /* @__PURE__ */ e.createElement("span", { className: "widget-cell" }, /* @__PURE__ */ e.createElement(ce, { def: x, optKey: a, settings: r, setSettings: o, disabled: l, customWidgets: d }), u && /* @__PURE__ */ e.createElement("button", { className: "reset-btn", onClick: _, title: "Reset to default", "data-testid": `reset-${a}` }, "↺")));
|
|
159
163
|
}
|
|
160
164
|
function fe({
|
|
161
165
|
schema: t = R,
|
|
@@ -163,14 +167,14 @@ function fe({
|
|
|
163
167
|
toggle: r = re,
|
|
164
168
|
settings: o,
|
|
165
169
|
setSettings: i,
|
|
166
|
-
onOptionOpen:
|
|
170
|
+
onOptionOpen: m,
|
|
167
171
|
embedded: d = !1,
|
|
168
172
|
customWidgets: c,
|
|
169
173
|
only: p,
|
|
170
174
|
overriddenKeys: x,
|
|
171
|
-
onRevertKey:
|
|
175
|
+
onRevertKey: b
|
|
172
176
|
}) {
|
|
173
|
-
const l = j(() => ne(a), [a]), [
|
|
177
|
+
const l = j(() => ne(a), [a]), [u, _] = y(p?.builder ?? l[0] ?? ""), [w, v] = y(0), [N, z] = y("all"), [E, n] = y(""), g = W(o), f = l.filter((s) => te(s) === g), S = p?.builder ?? (f.includes(u) ? u : f[0] ?? ""), M = a[p?.builder ?? S] ?? [], A = p?.page ? M.filter((s) => s.page === p.page) : M, O = A[Math.min(w, A.length - 1)], J = j(() => r.disabledKeys(r.makeCfg(o)), [o, r]), k = E.trim().toLowerCase(), C = j(() => k ? Object.entries(t).filter(([s, h]) => s.includes(k) || h.label?.toLowerCase().includes(k) || h.full_label?.toLowerCase().includes(k)).slice(0, 60).map(([s]) => s) : [], [k]), D = (s, h) => /* @__PURE__ */ e.createElement(
|
|
174
178
|
de,
|
|
175
179
|
{
|
|
176
180
|
schema: t,
|
|
@@ -179,16 +183,16 @@ function fe({
|
|
|
179
183
|
settings: o,
|
|
180
184
|
setSettings: i,
|
|
181
185
|
disabled: J,
|
|
182
|
-
onOptionOpen:
|
|
186
|
+
onOptionOpen: m,
|
|
183
187
|
customWidgets: c,
|
|
184
188
|
overridden: x?.includes(s),
|
|
185
|
-
onRevertKey:
|
|
189
|
+
onRevertKey: b
|
|
186
190
|
}
|
|
187
191
|
);
|
|
188
|
-
return /* @__PURE__ */ e.createElement(X, { css: Q + Y, className: d ? "sp-embedded" : void 0 }, /* @__PURE__ */ e.createElement("div", { className: "settings-panel" }, !p && /* @__PURE__ */ e.createElement("div", { className: "sp-top" }, /* @__PURE__ */ e.createElement("input", { className: "sp-search", placeholder: `Search options (${Object.keys(t).length})…`, value: E, onChange: (s) => n(s.target.value), "data-testid": "opt-search" }), !
|
|
189
|
-
|
|
190
|
-
} }, f.map((s) => /* @__PURE__ */ e.createElement("option", { key: s, value: s }, B(s))))), /* @__PURE__ */ e.createElement("div", { className: "sp-pages" }, A.map((s, h) => /* @__PURE__ */ e.createElement("button", { key: s.page + h, className: h === Math.min(w, A.length - 1) ? "on" : "", onClick: () => v(h) }, s.page))), /* @__PURE__ */ e.createElement("div", { className: "sp-modes" }, ee.map((s) => /* @__PURE__ */ e.createElement("button", { key: s, className:
|
|
191
|
-
const h = s.options.filter((F) => se(t, F,
|
|
192
|
+
return /* @__PURE__ */ e.createElement(X, { css: Q + Y, className: d ? "sp-embedded" : void 0 }, /* @__PURE__ */ e.createElement("div", { className: "settings-panel" }, !p && /* @__PURE__ */ e.createElement("div", { className: "sp-top" }, /* @__PURE__ */ e.createElement("input", { className: "sp-search", placeholder: `Search options (${Object.keys(t).length})…`, value: E, onChange: (s) => n(s.target.value), "data-testid": "opt-search" }), !k && /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement("label", { className: "sp-builder" }, /* @__PURE__ */ e.createElement("span", null, "Settings group"), /* @__PURE__ */ e.createElement("select", { value: S, onChange: (s) => {
|
|
193
|
+
_(s.target.value), v(0);
|
|
194
|
+
} }, f.map((s) => /* @__PURE__ */ e.createElement("option", { key: s, value: s }, B(s))))), /* @__PURE__ */ e.createElement("div", { className: "sp-pages" }, A.map((s, h) => /* @__PURE__ */ e.createElement("button", { key: s.page + h, className: h === Math.min(w, A.length - 1) ? "on" : "", onClick: () => v(h) }, s.page))), /* @__PURE__ */ e.createElement("div", { className: "sp-modes" }, ee.map((s) => /* @__PURE__ */ e.createElement("button", { key: s, className: N === s ? "on" : "", onClick: () => z(s) }, s))))), /* @__PURE__ */ e.createElement("div", { className: "sp-body" }, k ? /* @__PURE__ */ e.createElement("section", { "data-testid": "search-results" }, /* @__PURE__ */ e.createElement("h3", null, "Search: “", E, "” — ", C.length, " hit", C.length === 1 ? "" : "s", C.length === 60 ? "+" : ""), C.map(D), !C.length && /* @__PURE__ */ e.createElement("p", { className: "muted" }, "No matches")) : O ? /* @__PURE__ */ e.createElement(e.Fragment, null, !p && /* @__PURE__ */ e.createElement("h2", null, O.page, " ", /* @__PURE__ */ e.createElement("span", { className: "muted" }, "Tab.cpp:", O.line)), O.groups.map((s) => {
|
|
195
|
+
const h = s.options.filter((F) => se(t, F, N) && !(p && F.startsWith("<")));
|
|
192
196
|
return h.length ? /* @__PURE__ */ e.createElement("section", { key: s.group + s.line }, /* @__PURE__ */ e.createElement("h3", null, s.group || "(untitled group)", " ", /* @__PURE__ */ e.createElement("span", { className: "muted" }, ":", s.line)), h.map(D)) : null;
|
|
193
197
|
})) : /* @__PURE__ */ e.createElement("p", { className: "muted" }, "No builder"))));
|
|
194
198
|
}
|
package/dist/gcode_parse.js
CHANGED
|
@@ -1,32 +1,60 @@
|
|
|
1
|
-
import { D as
|
|
2
|
-
import { R as t, e as
|
|
3
|
-
import { T as
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
let
|
|
10
|
-
Array.isArray(i?.
|
|
11
|
-
const
|
|
12
|
-
|
|
1
|
+
import { D as At, a as St } from "./viewer_defaults-B7UUZ582.js";
|
|
2
|
+
import { R as t, S as ut, e as $ } from "./toolpath_encoding-BuYs95qZ.js";
|
|
3
|
+
import { T as mt } from "./toolpath_palette-B8xEl-qa.js";
|
|
4
|
+
const ht = ";_GP_FIRST_LINE_M73_PLACEHOLDER", gt = ";_GP_LAST_LINE_M73_PLACEHOLDER", Lt = "@PRINT_TIME_SEC@", pt = "@USED_FILAMENT_LENGTH@", Nt = (s) => Math.floor((Math.max(0, s) + 0.5) / 60), Z = (s, i) => `M73 P${s} R${i}`;
|
|
5
|
+
function Ct(s, i) {
|
|
6
|
+
let n = String(s ?? "");
|
|
7
|
+
const m = Number(i?.time_estimate) || 0;
|
|
8
|
+
if (n.includes(Lt) && (n = n.split(Lt).join(m.toFixed(2))), n.includes(pt) && (n = n.split(pt).join(((Number(i?.filament_mm) || 0) / 1e3).toFixed(2))), !n.includes(ht)) return n;
|
|
9
|
+
let a = [];
|
|
10
|
+
Array.isArray(i?.layer_times) && (a = i.layer_times);
|
|
11
|
+
const l = n.split(`
|
|
12
|
+
`), o = [];
|
|
13
|
+
let L = 0, E = 0, d = "";
|
|
14
|
+
for (const N of l) {
|
|
15
|
+
if (N === ht) {
|
|
16
|
+
d = Z(0, Nt(m)), o.push(d);
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (N === gt) {
|
|
20
|
+
o.push(Z(100, 0));
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (o.push(N), !N.startsWith("; LAYER ")) continue;
|
|
24
|
+
let A = 0;
|
|
25
|
+
m > 0 && (A = Math.min(100, Math.floor(100 * E / m)));
|
|
26
|
+
const S = Z(A, Nt(m - E));
|
|
27
|
+
S !== d && (o.push(S), d = S), E += Number(a[L]) || 0, L += 1;
|
|
28
|
+
}
|
|
29
|
+
return o.join(`
|
|
30
|
+
`);
|
|
13
31
|
}
|
|
14
|
-
|
|
15
|
-
|
|
32
|
+
const B = 1e-6, Mt = 254, Tt = /^(filament|extruder)_colour\s*=\s*(.*)$/i, It = (s) => s.split(/[;,]/).map((i) => {
|
|
33
|
+
const n = /^"?#?([0-9a-f]{6})(?:[0-9a-f]{2})?"?$/i.exec(i.trim());
|
|
34
|
+
return n ? "#" + n[1].toUpperCase() : null;
|
|
35
|
+
}), Pt = (s) => "#" + mt[s % mt.length].map((i) => Math.round(i * 255).toString(16).padStart(2, "0")).join("");
|
|
36
|
+
function Ot(s, i) {
|
|
37
|
+
let n = [];
|
|
38
|
+
Array.isArray(s?.colors) && (n = s.colors);
|
|
39
|
+
const m = i ?? [], a = Math.max(n.length, m.length, s?.filament_mm_by_tool?.length ?? 0);
|
|
40
|
+
return Array.from({ length: a }, (l, o) => n[o] || m[o] || Pt(o));
|
|
16
41
|
}
|
|
17
|
-
function
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
42
|
+
function Ut(s, i) {
|
|
43
|
+
return yt(s.gcode, Ot(s.stats, i));
|
|
44
|
+
}
|
|
45
|
+
function yt(s, i) {
|
|
46
|
+
const n = String(s ?? ""), m = [i].flat().filter(Boolean);
|
|
47
|
+
if (!m.length || /^;\s*filament_colour\s*=/mi.test(n)) return n;
|
|
48
|
+
const a = "; filament_colour = " + m.join(";") + `
|
|
49
|
+
`, l = n.lastIndexOf(`
|
|
22
50
|
; CONFIG_BLOCK_END`);
|
|
23
|
-
if (
|
|
24
|
-
let
|
|
51
|
+
if (l >= 0) return n.slice(0, l + 1) + a + n.slice(l + 1);
|
|
52
|
+
let o = `
|
|
25
53
|
`;
|
|
26
|
-
return (!
|
|
27
|
-
`)) && (
|
|
54
|
+
return (!n || n.endsWith(`
|
|
55
|
+
`)) && (o = ""), n + o + a;
|
|
28
56
|
}
|
|
29
|
-
const
|
|
57
|
+
const _t = {
|
|
30
58
|
// OrcaSlicer / PrusaSlicer ;TYPE: names
|
|
31
59
|
"outer wall": t.WALL,
|
|
32
60
|
"external perimeter": t.WALL,
|
|
@@ -69,7 +97,7 @@ const St = {
|
|
|
69
97
|
skin: t.SOLID,
|
|
70
98
|
"support-interface": t.SUPPORT,
|
|
71
99
|
"prime-tower": t.PRIME
|
|
72
|
-
},
|
|
100
|
+
}, Gt = [
|
|
73
101
|
["skirt/brim", t.SKIRT],
|
|
74
102
|
["skirt", t.SKIRT],
|
|
75
103
|
["walls", t.WALL],
|
|
@@ -80,7 +108,7 @@ const St = {
|
|
|
80
108
|
["support", t.SUPPORT],
|
|
81
109
|
["prime tower", t.PRIME],
|
|
82
110
|
["wipe_tower_real", t.PRIME]
|
|
83
|
-
],
|
|
111
|
+
], wt = (s, i) => s === i || i.length < s.length && " (:/".includes(s[i.length]) && s.startsWith(i), Wt = {
|
|
84
112
|
1: t.WALL,
|
|
85
113
|
2: t.WALL,
|
|
86
114
|
3: t.WALL,
|
|
@@ -99,136 +127,151 @@ const St = {
|
|
|
99
127
|
16: t.SUPPORT,
|
|
100
128
|
17: t.PRIME
|
|
101
129
|
};
|
|
102
|
-
function
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
130
|
+
function Ht(s, { center: i = { x: 0, y: 0 }, filamentDiameter: n, layerHeight: m } = {}) {
|
|
131
|
+
const a = bt(s, { filamentDiameter: n, defaultLayerHeight: m });
|
|
132
|
+
for (const l of a.layers) {
|
|
133
|
+
const o = l.paths;
|
|
134
|
+
for (let L = 0; L + ut <= o.length; L += ut)
|
|
135
|
+
o[L] -= i.x, o[L + 1] -= i.y, o[L + 4] -= i.x, o[L + 5] -= i.y;
|
|
136
|
+
}
|
|
137
|
+
return a;
|
|
138
|
+
}
|
|
139
|
+
function bt(s, i = {}) {
|
|
140
|
+
const n = Math.PI / 4 * (i.filamentDiameter > 0 ? i.filamentDiameter : At) ** 2, m = i.defaultLayerHeight > 0 ? i.defaultLayerHeight : St;
|
|
141
|
+
let a = 0, l = 0, o = 0, L = 0, E = !0, d = !0, N = 0, A = t.WALL, S = 0, g = null;
|
|
142
|
+
const y = [];
|
|
143
|
+
let x = !1, D = !0, v = NaN, q = 0, X = 0, V = 0;
|
|
144
|
+
const K = /* @__PURE__ */ new Set([0]), z = [];
|
|
145
|
+
let j = [], k = [], F = !1;
|
|
146
|
+
const J = () => {
|
|
147
|
+
A = t.WALL, S = 0;
|
|
148
|
+
}, C = (c, f = !1) => {
|
|
149
|
+
g = { z: c, p: [], w: [] }, y.push(g), D = !1, v = NaN, (f || !F) && J();
|
|
150
|
+
}, Rt = () => y.length > 1 ? y[y.length - 2].z : 0, Q = (c, f, P, O, T, r, e) => {
|
|
151
|
+
const p = Math.hypot(O - c, T - f, r - P);
|
|
152
|
+
if (!(p < B))
|
|
153
|
+
if (e > B) {
|
|
154
|
+
V += e, z[N] = (z[N] ?? 0) + e, D ? C(Number.isNaN(v) ? r : v) : !x && r > g.z + 1e-3 && C(r);
|
|
155
|
+
const I = $(A, N);
|
|
156
|
+
g.p.push(c, f, P, I, O, T, r, I);
|
|
157
|
+
const h = Math.max(0.02, g.z - Rt() || m), _ = S > 0 ? S : e * n / (p * h) + h * (1 - Math.PI / 4);
|
|
158
|
+
g.w.push(Math.min(3, Math.max(0.05, _))), q++;
|
|
159
|
+
} else g && (g.p.push(c, f, P, $(t.TRAVEL, N), O, T, r, $(t.TRAVEL, N)), g.w.push(0), X++);
|
|
123
160
|
};
|
|
124
|
-
for (const
|
|
161
|
+
for (const c of s.split(`
|
|
125
162
|
`)) {
|
|
126
|
-
const
|
|
127
|
-
if (
|
|
128
|
-
const e =
|
|
163
|
+
const f = c.indexOf(";"), P = (f < 0 ? c : c.slice(0, f)).trim(), O = f < 0 ? "" : c.slice(f + 1).trim();
|
|
164
|
+
if (O && !P) {
|
|
165
|
+
const e = O.toLowerCase(), p = Tt.exec(O);
|
|
129
166
|
if (p) {
|
|
130
|
-
p[1].toLowerCase() === "filament" ?
|
|
167
|
+
p[1].toLowerCase() === "filament" ? j = It(p[2]) : k = It(p[2]);
|
|
131
168
|
continue;
|
|
132
169
|
}
|
|
133
170
|
if (e.startsWith("type:")) {
|
|
134
|
-
|
|
171
|
+
A = _t[e.slice(5).trim()] ?? t.WALL, F = !0;
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (e.startsWith("feature:")) {
|
|
175
|
+
A = _t[e.slice(8).trim()] ?? t.WALL, F = !0;
|
|
135
176
|
continue;
|
|
136
177
|
}
|
|
137
178
|
if (e.startsWith("_extrusion_role:")) {
|
|
138
|
-
|
|
179
|
+
A = Wt[parseInt(e.slice(16), 10)] ?? t.WALL, F = !0;
|
|
139
180
|
continue;
|
|
140
181
|
}
|
|
141
|
-
if (e.startsWith("width:")) {
|
|
142
|
-
const
|
|
143
|
-
|
|
182
|
+
if (e.startsWith("width:") || e.startsWith("line_width:")) {
|
|
183
|
+
const _ = parseFloat(e.slice(e.indexOf(":") + 1));
|
|
184
|
+
S = 0, _ > 0 && (S = _);
|
|
144
185
|
continue;
|
|
145
186
|
}
|
|
146
|
-
if (e.startsWith("layer_change") || e.startsWith("layer:")) {
|
|
147
|
-
|
|
187
|
+
if (e.startsWith("layer_change") || e.startsWith("change_layer") || e.startsWith("layer:")) {
|
|
188
|
+
x = !0, D = !0, J();
|
|
148
189
|
continue;
|
|
149
190
|
}
|
|
150
|
-
if (e.startsWith("z:")) {
|
|
151
|
-
const
|
|
152
|
-
|
|
191
|
+
if (e.startsWith("z:") || e.startsWith("z_height:")) {
|
|
192
|
+
const _ = parseFloat(e.slice(e.indexOf(":") + 1));
|
|
193
|
+
D && _ > 0 && (x = !0, C(_));
|
|
153
194
|
continue;
|
|
154
195
|
}
|
|
155
|
-
const
|
|
156
|
-
if (
|
|
157
|
-
|
|
196
|
+
const I = /^layer \d+ z([-\d.]+)/.exec(e);
|
|
197
|
+
if (I) {
|
|
198
|
+
x = !0, C(parseFloat(I[1]), !0);
|
|
158
199
|
continue;
|
|
159
200
|
}
|
|
160
|
-
const
|
|
161
|
-
|
|
201
|
+
const h = Gt.find(([_]) => wt(e, _));
|
|
202
|
+
h && (A = h[1]);
|
|
162
203
|
continue;
|
|
163
204
|
}
|
|
164
|
-
if (!
|
|
165
|
-
const
|
|
166
|
-
if (
|
|
167
|
-
|
|
205
|
+
if (!P) continue;
|
|
206
|
+
const T = P.split(/\s+/), r = T[0].toUpperCase();
|
|
207
|
+
if (r === "G90") {
|
|
208
|
+
E = !0;
|
|
168
209
|
continue;
|
|
169
210
|
}
|
|
170
|
-
if (
|
|
171
|
-
|
|
211
|
+
if (r === "G91") {
|
|
212
|
+
E = !1;
|
|
172
213
|
continue;
|
|
173
214
|
}
|
|
174
|
-
if (
|
|
175
|
-
|
|
215
|
+
if (r === "M82") {
|
|
216
|
+
d = !0;
|
|
176
217
|
continue;
|
|
177
218
|
}
|
|
178
|
-
if (
|
|
179
|
-
|
|
219
|
+
if (r === "M83") {
|
|
220
|
+
d = !1;
|
|
180
221
|
continue;
|
|
181
222
|
}
|
|
182
|
-
if (/^T\d+$/.test(
|
|
183
|
-
const e = parseInt(
|
|
184
|
-
e <=
|
|
223
|
+
if (/^T\d+$/.test(r)) {
|
|
224
|
+
const e = parseInt(r.slice(1), 10);
|
|
225
|
+
e <= Mt && (N = e, K.add(N));
|
|
185
226
|
continue;
|
|
186
227
|
}
|
|
187
|
-
if (
|
|
188
|
-
let e = NaN, p = NaN,
|
|
189
|
-
for (let
|
|
190
|
-
const
|
|
191
|
-
Number.isNaN(
|
|
228
|
+
if (r === "G92" || r === "G0" || r === "G1" || r === "G2" || r === "G3") {
|
|
229
|
+
let e = NaN, p = NaN, I = NaN, h = NaN, _ = 0, et = 0;
|
|
230
|
+
for (let M = 1; M < T.length; M++) {
|
|
231
|
+
const u = T[M][0], R = parseFloat(T[M].slice(1));
|
|
232
|
+
Number.isNaN(R) || (u === "X" || u === "x" ? e = R : u === "Y" || u === "y" ? p = R : u === "Z" || u === "z" ? I = R : u === "E" || u === "e" ? h = R : u === "I" || u === "i" ? _ = R : (u === "J" || u === "j") && (et = R));
|
|
192
233
|
}
|
|
193
|
-
if (
|
|
194
|
-
Number.isNaN(e) || (
|
|
234
|
+
if (r === "G92") {
|
|
235
|
+
Number.isNaN(e) || (a = e), Number.isNaN(p) || (l = p), Number.isNaN(I) || (o = I), Number.isNaN(h) || (L = h);
|
|
195
236
|
continue;
|
|
196
237
|
}
|
|
197
|
-
const
|
|
198
|
-
if (
|
|
199
|
-
const
|
|
200
|
-
let
|
|
201
|
-
const nt =
|
|
202
|
-
nt &&
|
|
203
|
-
const
|
|
204
|
-
let
|
|
205
|
-
for (let
|
|
206
|
-
const
|
|
207
|
-
|
|
238
|
+
const U = Number.isNaN(e) ? a : E ? e : a + e, H = Number.isNaN(p) ? l : E ? p : l + p, Y = Number.isNaN(I) ? o : E ? I : o + I, it = Number.isNaN(h) ? 0 : d ? h - L : h;
|
|
239
|
+
if (r === "G2" || r === "G3") {
|
|
240
|
+
const M = a + _, u = l + et, R = Math.hypot(a - M, l - u), b = Math.atan2(l - u, a - M);
|
|
241
|
+
let G = Math.atan2(H - u, U - M);
|
|
242
|
+
const nt = r === "G3";
|
|
243
|
+
nt && G <= b + B && (G += 2 * Math.PI), !nt && G >= b - B && (G -= 2 * Math.PI);
|
|
244
|
+
const w = Math.max(1, Math.min(360, Math.ceil(Math.abs(G - b) * R / 0.3)));
|
|
245
|
+
let st = a, ot = l, rt = o;
|
|
246
|
+
for (let W = 1; W <= w; W++) {
|
|
247
|
+
const at = b + (G - b) * W / w, lt = W === w ? U : M + R * Math.cos(at), ct = W === w ? H : u + R * Math.sin(at), ft = o + (Y - o) * W / w;
|
|
248
|
+
Q(st, ot, rt, lt, ct, ft, it / w), st = lt, ot = ct, rt = ft;
|
|
208
249
|
}
|
|
209
250
|
} else
|
|
210
|
-
|
|
211
|
-
|
|
251
|
+
Q(a, l, o, U, H, Y, it);
|
|
252
|
+
a = U, l = H, o = Y, Number.isNaN(h) || (L = d ? h : L + h);
|
|
212
253
|
}
|
|
213
254
|
}
|
|
214
|
-
const
|
|
255
|
+
const Et = Math.max(j.length, k.length), tt = Array.from({ length: Et }, (c, f) => k[f] || j[f] || null), dt = Array.from({ length: Math.max(...K) + 1 }, (c, f) => z[f] || 0);
|
|
215
256
|
return {
|
|
216
|
-
layers:
|
|
257
|
+
layers: y.map((c) => ({ z: c.z, paths: Float32Array.from(c.p), widths: Float32Array.from(c.w) })),
|
|
217
258
|
stats: {
|
|
218
|
-
layers:
|
|
259
|
+
layers: y.length,
|
|
219
260
|
path_segments: q,
|
|
220
261
|
travel_segments: X,
|
|
221
|
-
filament_mm:
|
|
222
|
-
tools: [...
|
|
262
|
+
filament_mm: V,
|
|
263
|
+
tools: [...K].sort((c, f) => c - f),
|
|
223
264
|
// The kernel's own stat name, so the Filament-view switch and the stats card's per-tool split work unchanged.
|
|
224
|
-
filament_mm_by_tool:
|
|
225
|
-
...
|
|
265
|
+
filament_mm_by_tool: dt,
|
|
266
|
+
...tt.some(Boolean) && { colors: tt }
|
|
226
267
|
}
|
|
227
268
|
};
|
|
228
269
|
}
|
|
229
270
|
export {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
271
|
+
Ut as exportedGcode,
|
|
272
|
+
Ct as finalizeGcode,
|
|
273
|
+
bt as parseGcode,
|
|
274
|
+
Ht as previewFromGcode,
|
|
275
|
+
Ot as resultToolColors,
|
|
276
|
+
yt as withFilamentColours
|
|
234
277
|
};
|