three-slicer 0.1.2 → 0.1.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/README.md +67 -8
- package/components/README.md +1 -1
- package/components/dist/SettingsPanel.js +12 -12
- package/data/README.md +39 -2
- package/data/config-schema.json +1163 -900
- package/data/filaments.js +2 -0
- package/data/invalidation-map.json +5 -4
- package/data/printers.json +1 -0
- package/data/processes.js +2 -0
- package/data/toggle-rules.json +44 -44
- package/data/ui-tree.json +190 -495
- package/engine/README.md +56 -4
- package/engine/src/data.js +9 -1
- package/engine/src/settings.js +218 -6
- package/engine/src/slicer.worker.js +142 -5
- package/engine/src/slicer_core.js +0 -0
- package/engine/src/slicer_core.mt.js +0 -0
- package/package.json +18 -3
- package/types/data/filaments.js.d.ts +27 -0
- package/types/data/printers.json.d.ts +23 -0
- package/types/data/processes.js.d.ts +21 -0
- package/types/data.d.ts +12 -2
- package/types/settings-keys.d.ts +48 -3
- package/types/settings.d.ts +30 -0
- package/types/viewer-gcode.d.ts +29 -0
- package/types/viewer-toolpath.d.ts +9 -1
- package/types/viewer.d.ts +53 -0
- package/viewer/README.md +48 -2
- package/viewer/dist/Viewport.js +2484 -1521
- package/viewer/dist/gcode_parse.js +190 -0
- package/viewer/dist/toolpath_gpu.js +162 -137
- package/viewer/styles.css +71 -2
package/viewer/dist/Viewport.js
CHANGED
|
@@ -1,1348 +1,1714 @@
|
|
|
1
|
-
import e, { useRef as
|
|
2
|
-
import { deriveKernelParams as
|
|
3
|
-
import { schema as
|
|
4
|
-
import { createPortal as
|
|
5
|
-
import { SUPPORTED_EXT as
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
import e, { useRef as ne, useState as ae, useLayoutEffect as aa, useEffect as Te, useMemo as _t } from "react";
|
|
2
|
+
import { deriveKernelParams as ln, settingRaw as He, printersByVendor as oa, processPresets as la, printerDefaultPreset as sa, printerKeys as St, machineLimitKeys as ia, printerSettings as ca, filamentPresets as da } from "three-slicer/settings";
|
|
3
|
+
import { uiTree as pa, schema as Un } from "three-slicer/data";
|
|
4
|
+
import { createPortal as ua } from "react-dom";
|
|
5
|
+
import { SUPPORTED_EXT as an, fileExt as ma, loadModel as fa, splitConnectedComponents as ha } from "./model_loaders.js";
|
|
6
|
+
import { parseGcode as ba } from "./gcode_parse.js";
|
|
7
|
+
import * as W from "three";
|
|
8
|
+
import { OrbitControls as ga } from "three/examples/jsm/controls/OrbitControls.js";
|
|
9
|
+
import { TransformControls as ya } from "three/examples/jsm/controls/TransformControls.js";
|
|
10
|
+
import { makeSlicerWorker as xa } from "./make_worker.js";
|
|
11
|
+
import { roleRatios as er, computeColors as Wn, buildSegmentData as va, makeToolpath as wa, VIEW_TYPES as Ea, TOOL_COLOR as Hn, DEFAULT_RANGES_COLORS as ka } from "./toolpath_gpu.js";
|
|
12
|
+
function _a({ css: t, className: r, children: c }) {
|
|
13
|
+
const i = ne(null), [o] = ae(() => {
|
|
14
|
+
const p = document.createElement("div");
|
|
15
|
+
return p.style.display = "contents", p;
|
|
15
16
|
});
|
|
16
|
-
return
|
|
17
|
-
const
|
|
18
|
-
let
|
|
19
|
-
|
|
20
|
-
}, [
|
|
17
|
+
return aa(() => {
|
|
18
|
+
const p = i.current, h = p.shadowRoot || p.attachShadow({ mode: "open" });
|
|
19
|
+
let j = h.querySelector("style[data-ts-css]");
|
|
20
|
+
j || (j = document.createElement("style"), j.setAttribute("data-ts-css", ""), h.append(j)), j.textContent = t, h.contains(o) || h.append(o);
|
|
21
|
+
}, [t, o]), /* @__PURE__ */ e.createElement("div", { ref: i, className: r }, ua(c, o));
|
|
21
22
|
}
|
|
22
|
-
const Jn = ':host{display:contents}*{box-sizing:border-box}.app-shell{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;flex-direction:column;background:#0e1216;color:#cdd6dd;font:14px/1.5 -apple-system,Segoe UI,sans-serif}.app-body{flex:1 1 auto;display:flex;min-height:0}.topbar{flex:0 0 44px;height:44px;display:flex;align-items:center;padding:0 12px;gap:10px;background:#161b21;border-bottom:1px solid #262d35}.topbar .tb-left,.topbar .tb-right{flex:1 1 0;display:flex;align-items:center;gap:8px}.topbar .tb-right{justify-content:flex-end}.tb-logo{font-size:15px;color:#e6edf3;letter-spacing:.01em}.tb-logo b{color:#00ae42}.tb-re{font-size:10px;background:#00ae42;color:#fff;padding:1px 5px;border-radius:4px;margin-left:2px}.tb-btn{display:inline-flex;align-items:center;gap:5px;background:#20272f;border:1px solid #2c353d;color:#cdd6dd;border-radius:6px;padding:4px 10px;cursor:pointer;font-size:12px}.tb-btn img{width:15px;height:15px}.tb-btn:hover{background:#28313a}.tb-tabs{display:flex;border:1px solid #2c353d;border-radius:8px;overflow:hidden;flex:0 0 auto}.tb-tabs button{padding:6px 24px;border:0;background:#1a2027;color:#9fb3c0;font-weight:600;font-size:13px;cursor:pointer}.tb-tabs button.on{background:#00ae42;color:#fff}.tb-tabs button:disabled{color:#5a6570;cursor:not-allowed}.tb-icon{width:28px;height:28px;border:1px solid #2c353d;background:#20272f;color:#7d8b96;border-radius:6px;font-size:15px;cursor:not-allowed}.left-rail{flex:0 0 48px;display:flex;flex-direction:column;align-items:center;gap:6px;padding:9px 0;background:#12171c;border-right:1px solid #232a31}.left-rail button{width:36px;height:36px;border:1px solid transparent;border-radius:8px;background:transparent;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0}.left-rail button img{width:21px;height:21px;opacity:.72}.left-rail button:hover{background:#1e252c}.left-rail button.on{background:#00ae42}.left-rail button.on img{opacity:1;filter:brightness(1.6)}.rail-sep{width:26px;height:1px;background:#2a323a;margin:3px 0}.viewport-col{position:relative;flex:1 1 auto;min-width:0;background:#161a1e}.vp-top-toolbar{position:absolute;top:12px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:3px;background:#12171cd9;padding:4px;border-radius:9px;border:1px solid #2a323a;z-index:3;max-width:calc(100% - 24px);overflow-x:auto;scrollbar-width:none}.vp-top-toolbar::-webkit-scrollbar{display:none}.vp-top-toolbar>*{flex:0 0 auto}.vp-top-toolbar button{width:32px;height:32px;border:0;background:transparent;border-radius:6px;cursor:pointer;display:flex;align-items:center;justify-content:center}.vp-top-toolbar button img{width:18px;height:18px;opacity:.82}.vp-top-toolbar button:hover:not(:disabled){background:#2a333c}.vp-top-toolbar button:disabled{opacity:.32;cursor:not-allowed}.vtt-sep{width:1px;align-self:stretch;background:#333c45;margin:3px}.plate-bar{position:absolute;right:14px;bottom:30px;display:flex;align-items:center;gap:4px;z-index:3;background:#12171cd9;border:1px solid #2a323a;border-radius:9px;padding:4px}.plate-bar button{min-width:26px;height:26px;border:1px solid #2c353d;background:#1a2027;color:#9fb3c0;border-radius:6px;cursor:pointer;font-size:12px;font-weight:600}.plate-tab.on{background:#00ae42;color:#fff;border-color:#00ae42}.plate-add{color:#7ad19a!important}.plate-del{color:#e08a8a!important}.plate-bar button:disabled{opacity:.4;cursor:not-allowed}.slice-dd{position:relative;flex:1.4}.slice-dd .slice-btn{width:100%}.slice-menu{position:absolute;bottom:calc(100% + 6px);left:0;right:0;background:#fff;border:1px solid #d5d8dd;border-radius:8px;box-shadow:0 4px 16px #0000002e;overflow:hidden;z-index:10}.slice-menu button{display:block;width:100%;text-align:left;padding:9px 12px;border:0;background:#fff;color:#24282e;cursor:pointer;font-size:13px}.slice-menu button:hover{background:#eef7f1}.brush-panel{position:absolute;top:58px;left:14px;width:214px;background:#161b21f2;border:1px solid #2c353d;border-radius:10px;padding:10px;z-index:4;box-shadow:0 3px 14px #00000073}.bp-title{font-weight:600;margin-bottom:6px;color:#cdd6dd}.bp-modes{display:flex;gap:4px;flex-wrap:wrap}.bp-modes button{padding:3px 9px;border:1px solid #2c353d;background:#1a2027;color:#cdd6dd;border-radius:5px;cursor:pointer;font-size:12px}.bp-modes button.enf.on{background:#2b6cff;color:#fff;border-color:#2b6cff}.bp-modes button.blk.on{background:#e23b3b;color:#fff;border-color:#e23b3b}.bp-radius{display:block;font-size:12px;color:#aebcc6;margin-top:8px}.bp-radius input{width:100%}.bp-counts{margin-top:6px;font-size:11px}.stats-card{position:absolute;left:14px;bottom:32px;background:#161b21ed;border:1px solid #2c353d;border-radius:10px;padding:10px 14px;font-size:13px;line-height:1.7;z-index:2;color:#cdd6dd}.stats-card b{color:#9fe3bd}.sidebar{flex:0 0 384px;width:384px;display:flex;flex-direction:column;background:#eef0f2;color:#24282e;border-left:1px solid #d5d8dd;min-height:0}.sidebar-scroll{flex:1 1 auto;overflow-y:auto;padding:10px;display:flex;flex-direction:column;gap:10px}.side-card{background:#fff;border:1px solid #e2e4e8;border-radius:10px;padding:10px 12px}.sc-head{font-weight:700;font-size:13px;color:#2a2f36;display:flex;align-items:center;gap:6px;margin-bottom:7px}.sc-count{background:#00ae42;color:#fff;font-size:10px;border-radius:8px;padding:0 6px;font-weight:700}.sc-head-btns{margin-left:auto;display:flex;gap:4px}.sc-head-btns button{width:22px;height:22px;border:1px solid #d3d6db;background:#f6f7f8;border-radius:5px;cursor:pointer;font-size:14px;line-height:1;color:#333}.sc-head-btns button:disabled{opacity:.4;cursor:not-allowed}.sc-info{display:flex;justify-content:space-between;font-size:12px;color:#5a6069;padding:2px 0}.sc-info b{color:#24282e}.side-warn{margin:0 2px;font-size:12px}.filament-row{display:flex;align-items:center;gap:8px;padding:3px 0}.filament-row input[type=color]{width:28px;height:22px;border:1px solid #ccc;border-radius:5px;padding:0;cursor:pointer;background:none}.fil-t{font-weight:700;font-size:12px;width:20px}.fil-swatch{width:15px;height:15px;border-radius:4px;border:1px solid rgba(0,0,0,.15)}.fil-hex{font-size:11px;margin-left:auto}.obj-list2{list-style:none;margin:0 0 6px;padding:0}.obj-list2 li{display:flex;align-items:center;gap:6px;padding:3px 0;font-size:12px}.obj-list2 li.obj-hidden{opacity:.5}.obj-eye{border:0;background:none;cursor:pointer;font-size:13px;padding:0}.obj-list2 .obj-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#24282e}.obj-list2 .obj-ext{border:1px solid #d0d3d8;border-radius:5px;font-size:11px;padding:1px 3px;background:#fff}.obj-del{border:0;background:#fbe9ec;color:#d0435a;border-radius:5px;cursor:pointer;padding:0 6px}.side-card .slice-support{color:#444;font-size:12px;margin:5px 0 0}.process-card{padding:8px}.side-card .view-type-row{color:#444}.side-card .view-type-row select,.side-card .obj-ext{background:#fff;color:#222;border:1px solid #ccd0d5}.side-card .slice-layer label{color:#444;font-size:12px}.side-card .grad-title{color:#333}.side-card .grad-minmax{color:#666}.side-card .role-legend,.side-card .slice-travel{color:#555}.side-card .layer-ctl button{background:#f1f2f4;color:#333;border:1px solid #d3d6db}.side-card .layer-ctl button.on{background:#00ae42;color:#fff;border-color:#00ae42}.side-bottom{flex:0 0 auto;display:flex;gap:8px;padding:10px;border-top:1px solid #dcdfe3;background:#e6e9ec}.side-bottom .slice-btn{flex:1.4;margin:0}.auto-slice{display:flex;align-items:center;gap:5px;font-size:12px;color:#444;cursor:pointer;white-space:nowrap;-webkit-user-select:none;user-select:none}.auto-slice input{margin:0}.export-btn{flex:1;text-align:center;padding:9px;border-radius:8px;background:#dfe6ea;color:#1f6feb;border:1px solid #c7d2da;text-decoration:none;font-weight:600;cursor:pointer;font-size:13px}.export-btn:hover{background:#d3dee4}.export-btn:disabled{color:#9aa4ad;background:#e9ecef;cursor:not-allowed}.vp-canvas{position:absolute;top:0;right:0;bottom:0;left:0}.vp-canvas canvas{display:block}.vp-canvas.fail{display:flex;align-items:center;justify-content:center}.vp-fallback{color:#f0c9a8;padding:24px;text-align:center;max-width:560px;line-height:1.5}.vp-status{position:absolute;bottom:8px;left:12px;right:12px;z-index:1;font-size:11.5px;color:#9fe3bd;font-family:ui-monospace,monospace;text-shadow:0 1px 2px #000;pointer-events:none}.slice-warn{color:#f0c060;margin:4px 0}.sc-sub{font-size:10.5px;opacity:.62;margin:1px 0 3px}.sc-fold>summary{display:flex;justify-content:space-between;align-items:center;font-size:12px;color:#5a6069;padding:2px 0;cursor:pointer;list-style:none}.sc-fold>summary::-webkit-details-marker{display:none}.sc-fold-lbl:before{content:"▸";display:inline-block;width:10px;font-size:9px;opacity:.5}.sc-fold[open] .sc-fold-lbl:before{content:"▾"}.sc-fold>summary b{color:#24282e}.sc-fold[open]>summary{border-bottom:1px solid #e3e6ea;margin-bottom:4px}.sc-fold-body{max-height:320px;overflow-y:auto}.sc-model{max-width:62%;font-size:11.5px;padding:1px 2px}.support-tools{display:flex;align-items:center;justify-content:space-between;gap:8px;margin:2px 0 2px 16px;padding-left:6px;border-left:2px solid #e3e6ea}.sup-style{margin-left:16px;padding-left:6px;border-left:2px solid #e3e6ea}.sup-paint{font-size:11px;padding:2px 8px;border:1px solid #c9ced6;border-radius:5px;background:#fff;color:#24282e;cursor:pointer;white-space:nowrap}.sup-paint.on{background:#2b6cff;border-color:#2b6cff;color:#fff}.sup-paint:disabled{opacity:.45;cursor:not-allowed}.slice-btn{width:100%;margin-top:6px;padding:7px;border:0;border-radius:7px;background:#00ae42;color:#fff;font-weight:700;cursor:pointer}.slice-btn:disabled{background:#3a4650;color:#8b98a2;cursor:not-allowed}.slice-err{color:#ff8b8b;margin-top:6px}.slice-stats{margin-top:8px;line-height:1.5}.slice-stats b{color:#9fe3bd}.slice-layer{margin-top:8px;display:flex;flex-direction:column;gap:4px}.slice-layer input[type=range]{width:100%}.slice-travel{color:#aebcc6;display:flex;align-items:center;gap:4px}.view-type-row{display:flex;align-items:center;justify-content:space-between;gap:6px;color:#aebcc6}.view-type-row select{flex:1;background:#10141a;color:#eee;border:1px solid #2c353d;border-radius:4px;padding:2px 4px}.dual-slider{position:relative;height:22px}.dual-slider input[type=range]{position:absolute;left:0;top:0;width:100%;margin:0;pointer-events:none;background:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.dual-slider input[type=range]::-webkit-slider-thumb{pointer-events:auto;-webkit-appearance:none;width:13px;height:13px;border-radius:50%;background:#00ae42;border:2px solid #0c1013;cursor:pointer}.dual-slider input[type=range]::-moz-range-thumb{pointer-events:auto;width:13px;height:13px;border-radius:50%;background:#00ae42;border:2px solid #0c1013;cursor:pointer}.dual-slider input[type=range]::-webkit-slider-runnable-track{height:4px;background:#2c353d;border-radius:2px}.dual-slider input[type=range]:first-child{z-index:2}.layer-ctl{display:flex;align-items:center;gap:8px}.layer-ctl button{padding:2px 8px;border:1px solid #2c353d;border-radius:5px;background:#1a2027;color:#cdd6dd;font-size:11px;cursor:pointer}.layer-ctl button.on{background:#00ae42;color:#fff;border-color:#00ae42}.grad-legend{margin-top:6px}.grad-title{font-size:11px;color:#cdd6dd;margin-bottom:3px}.grad-bar{height:10px;border-radius:3px;border:1px solid #2c353d}.grad-minmax{display:flex;justify-content:space-between;font-size:10px;color:#aebcc6;margin-top:2px}.role-legend{display:flex;flex-wrap:wrap;gap:4px 10px;margin-top:6px;font-size:11px;color:#aebcc6}.role-item{display:inline-flex;align-items:center;gap:4px}.role-item i{width:10px;height:6px;border-radius:2px;display:inline-block}.role-item b{color:#cdd6dd}.vp-canvas.drag-over{outline:3px dashed #00ae42;outline-offset:-6px}.empty-hint{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;pointer-events:none;color:#9fb3c0;text-align:center}.empty-hint .eh-icon{font-size:46px;opacity:.8}.empty-hint .eh-title{font-size:16px;font-weight:600;color:#cdd6dd}.empty-hint .eh-sub{font-size:12px;color:#7d8b96;letter-spacing:.04em}.empty-hint .eh-btn{pointer-events:auto;margin-top:8px;padding:7px 18px;border:0;border-radius:7px;background:#00ae42;color:#fff;font-weight:600;cursor:pointer}.empty-hint .eh-btn:hover{background:#06c04d}.drop-overlay{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;background:#00ae4224;color:#d7f7e3;font-size:18px;font-weight:700;pointer-events:none;border:3px dashed #00ae42;box-sizing:border-box}.obj-split{border:0;background:transparent;cursor:pointer;padding:0 3px;line-height:0}.obj-split img{width:13px;height:13px;opacity:.6}.obj-split:hover img{opacity:1}.ctx-scrim{position:absolute;top:0;right:0;bottom:0;left:0;z-index:24}.ctx-menu{position:absolute;z-index:25;min-width:168px;padding:4px;background:#1b2027;border:1px solid #2f3944;border-radius:8px;box-shadow:0 8px 24px #00000080}.ctx-menu button{display:flex;width:100%;align-items:center;justify-content:space-between;gap:16px;padding:6px 10px;border:0;border-radius:5px;background:transparent;color:#dfe6ee;font-size:12px;text-align:left;cursor:pointer}.ctx-menu button:hover:not(:disabled){background:#273140}.ctx-menu button:disabled{color:#64707d;cursor:not-allowed}.ctx-menu button.danger:hover:not(:disabled){background:#4a2229;color:#ffb3b3}.ctx-menu hr{margin:4px 6px;border:0;border-top:1px solid #2f3944}.ctx-key{color:#7d8b96;font-family:ui-monospace,monospace;font-size:11px}.help-overlay{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;background:#080c10b8;z-index:20}.help-card{background:#1b2027;color:#dfe6ee;border:1px solid #2f3944;border-radius:10px;padding:18px 22px;max-width:720px;box-shadow:0 12px 40px #00000080}.help-card h3{margin:0 0 12px;font-size:15px}.help-card h4{margin:0 0 6px;font-size:12px;color:#00ae42;text-transform:uppercase;letter-spacing:.04em}.help-cols{display:flex;gap:26px;flex-wrap:wrap}.help-card dl{display:grid;grid-template-columns:auto 1fr;gap:3px 12px;margin:0;font-size:12px}.help-card dt{color:#9fb0c2;font-family:ui-monospace,monospace;white-space:nowrap}.help-card dd{margin:0}.slice-support{display:flex;align-items:center;gap:5px;margin:6px 0;color:#cdd6dd;font-size:12px}.slice-support .muted{font-size:10px}.sc-bed{display:inline-flex;align-items:center;gap:4px;font-weight:700;color:#222}.sc-bed input{width:54px;padding:1px 4px;font-size:12px;font-weight:600;text-align:right;border:1px solid #ccd0d5;border-radius:5px;background:#fff;color:#222}', Qn = 40, Ye = (n) => n + Qn, Vt = 9, gt = (n) => {
|
|
23
|
-
const
|
|
24
|
-
return
|
|
25
|
-
}, er = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M.5,13.5V1.5a1,1,0,0,1,1-1h12a1,1,0,0,1,1,1v12a1,1,0,0,1-1,1H1.5A1,1,0,0,1,.5,13.5Zm3-6h3m2,0h3m-4-4v8" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), tr = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><path d="M33.5,35H5.5A1.5,1.5,0,0,1,4,33.5V5.5A1.5,1.5,0,0,1,5.5,4h28A1.5,1.5,0,0,1,35,5.5v28A1.5,1.5,0,0,1,33.5,35ZM5.5,5a.5.5,0,0,0-.5.5v28a.5.5,0,0,0,.5.5h28a.5.5,0,0,0,.5-.5V5.5a.5.5,0,0,0-.5-.5Z" style="fill:#b6b6b6"/><path d="M30.5,32H8.5A1.5,1.5,0,0,1,7,30.5v-6A1.5,1.5,0,0,1,8.5,23h22A1.5,1.5,0,0,1,32,24.5v6A1.5,1.5,0,0,1,30.5,32Zm-22-8a.5.5,0,0,0-.5.5v6a.5.5,0,0,0,.5.5h22a.5.5,0,0,0,.5-.5v-6a.5.5,0,0,0-.5-.5Zm22-2h-6A1.5,1.5,0,0,1,23,20.5V8.5A1.5,1.5,0,0,1,24.5,7h6A1.5,1.5,0,0,1,32,8.5v12A1.5,1.5,0,0,1,30.5,22Zm-6-14a.5.5,0,0,0-.5.5v12a.5.5,0,0,0,.5.5h6a.5.5,0,0,0,.5-.5V8.5a.5.5,0,0,0-.5-.5Zm-6,6h-8a3.5,3.5,0,0,1,0-7h8a3.5,3.5,0,0,1,0,7Zm-8-6a2.5,2.5,0,0,0,0,5h8a2.5,2.5,0,0,0,0-5Zm8,14A3.5,3.5,0,1,1,22,18.5,3.5,3.5,0,0,1,18.5,22Zm0-6A2.5,2.5,0,1,0,21,18.5,2.5,2.5,0,0,0,18.5,16Zm-8,6A3.5,3.5,0,1,1,14,18.5,3.5,3.5,0,0,1,10.5,22Zm0-6A2.5,2.5,0,1,0,13,18.5,2.5,2.5,0,0,0,10.5,16Z" style="fill:#009688"/></svg>'), nr = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M6.2,8a2.6,2.6,0,1,0,5.2,0a2.6,2.6,0,1,0,-5.2,0" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M4.6,8a2.6,2.6,0,1,0,5.2,0a2.6,2.6,0,1,0,-5.2,0" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), rr = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M.5,13.5V1.5a1,1,0,0,1,1-1h12a1,1,0,0,1,1,1v12a1,1,0,0,1-1,1H1.5A1,1,0,0,1,.5,13.5Z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M3.5,9h2m2,0h2m2,0h2" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M8,3.5l1.8,3h-3.6z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), Ft = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M.5,13.5V1.5a1,1,0,0,1,1-1h12a1,1,0,0,1,1,1v12a1,1,0,0,1-1,1H1.5A1,1,0,0,1,.5,13.5Zm3-6h8" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), or = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M.5,13.5V1.5a1,1,0,0,1,1-1h12a1,1,0,0,1,1,1v12a1,1,0,0,1-1,1H1.5A1,1,0,0,1,.5,13.5Z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M5,5l6,6" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M11,5l-6,6" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), ar = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M4,4h5v5H4z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M7,7h5v5H7z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), lr = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M8,3a5.93,5.93,0,0,0-4.95,2.5A9.1,9.1,0,0,0,1,8a9.1,9.1,0,0,0,2.05,2.5A5.93,5.93,0,0,0,8,13a5.93,5.93,0,0,0,4.95-2.5A9.1,9.1,0,0,0,15,8a9.1,9.1,0,0,0-2.05-2.5A5.93,5.93,0,0,0,8,3m0,8a2,2,0,1,1,2-2A2,2,0,0,1,8,11" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), sr = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M1.5,2.5l13,11" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M8,3a5.93,5.93,0,0,0-4.95,2.5A9.1,9.1,0,0,0,1,8a9.1,9.1,0,0,0,2.05,2.5" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M8,3a5.93,5.93,0,0,1,4.95,2.5A9.1,9.1,0,0,1,15,8a9.1,9.1,0,0,1-2.05,2.5" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><circle cx="8" cy="8" r="2" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), ir = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M2.5,8h11" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M2.5,6v4" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M13.5,6v4" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M6,7v2" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M10,7v2" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), cr = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M4,8a4,4,0,1,0,8,0a4,4,0,1,0,-8,0" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M8,4a4,4,0,0,1,0,8z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1;fill:#949494;stroke:none"/></svg>'), dr = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><path d="M34.854,19.146l-4-4a.5.5,0,0,0-.708.708L33.293,19H28.5a.5.5,0,0,0,0,1h4.793l-3.147,3.146a.5.5,0,0,0,.708.708l4-4A.5.5,0,0,0,34.854,19.146Z" style="fill:#009688"/><path d="M19.854,4.146a.5.5,0,0,0-.708,0l-4,4a.5.5,0,0,0,.708.708L19,5.707V10.5a.5.5,0,0,0,1,0V5.707l3.146,3.147a.5.5,0,0,0,.708-.708Z" style="fill:#009688"/><path d="M23.146,30.146,20,33.293V28.5a.5.5,0,0,0-1,0v4.793l-3.146-3.147a.5.5,0,0,0-.708.708l4,4a.5.5,0,0,0,.708,0l4-4a.5.5,0,0,0-.708-.708Z" style="fill:#009688"/><path d="M10.5,19H5.707l3.147-3.146a.5.5,0,0,0-.708-.708l-4,4a.5.5,0,0,0,0,.708l4,4a.5.5,0,0,0,.708-.708L5.707,20H10.5a.5.5,0,0,0,0-1Z" style="fill:#009688"/><path d="M24.5,26h-10A1.5,1.5,0,0,1,13,24.5v-10A1.5,1.5,0,0,1,14.5,13h10A1.5,1.5,0,0,1,26,14.5v10A1.5,1.5,0,0,1,24.5,26Zm-10-12a.5.5,0,0,0-.5.5v10a.5.5,0,0,0,.5.5h10a.5.5,0,0,0,.5-.5v-10a.5.5,0,0,0-.5-.5Z" style="fill:#b6b6b6"/></svg>'), pr = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M.5,13.5V1.5a1,1,0,0,1,1-1h12a1,1,0,0,1,1,1v12a1,1,0,0,1-1,1H1.5A1,1,0,0,1,.5,13.5Z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M5,5h6v6H5z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1;stroke-dasharray:2 1.5"/></svg>'), ur = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M.5,13.5V1.5a1,1,0,0,1,1-1h12a1,1,0,0,1,1,1v12a1,1,0,0,1-1,1H1.5A1,1,0,0,1,.5,13.5Z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M8,3.5v5m-2-2 2,2 2-2" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M4,11.5h8" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), mr = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><path d="M34.923,10.25a.392.392,0,0,0-.033-.05.5.5,0,0,0-.2-.162l0,0-15-6a.5.5,0,0,0-.372,0l-15,6,0,0a.5.5,0,0,0-.2.162.392.392,0,0,0-.033.05A.478.478,0,0,0,4,10.5v18a.464.464,0,0,0,.028.138.429.429,0,0,0,.011.054l.01.015a.51.51,0,0,0,.1.144l.008,0a.5.5,0,0,0,.156.1l0,0,14.989,6,0,0,.006,0a.5.5,0,0,0,.372,0l.006,0,0,0,1.989-.8a.5.5,0,0,0-.372-.928L20,33.762V16.839l14-5.6V21.5a.5.5,0,0,0,1,0v-11A.481.481,0,0,0,34.923,10.25ZM19,33.762l-14-5.6V11.239l14,5.6Zm.5-17.8L5.846,10.5,19.5,5.039,33.153,10.5Z" style="fill:#b6b6b6"/><path d="M33.5,24h-8A1.5,1.5,0,0,0,24,25.5v8A1.5,1.5,0,0,0,25.5,35h8A1.5,1.5,0,0,0,35,33.5v-8A1.5,1.5,0,0,0,33.5,24Zm.5,9.5a.5.5,0,0,1-.5.5h-8a.5.5,0,0,1-.5-.5v-8a.5.5,0,0,1,.5-.5h8a.5.5,0,0,1,.5.5Z" style="fill:#009688"/><path d="M32.5,29H30V26.5a.5.5,0,0,0-1,0V29H26.5a.5.5,0,0,0,0,1H29v2.5a.5.5,0,0,0,1,0V30h2.5a.5.5,0,0,0,0-1Z" style="fill:#009688"/></svg>'), fr = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><path d="M25.5,22a.5.5,0,0,1-.5-.5V18H18v3.5a.5.5,0,0,1-1,0v-6a.5.5,0,0,1,.084-.277l2-3A.5.5,0,0,1,19.5,12h4a.5.5,0,0,1,.416.223l2,3A.5.5,0,0,1,26,15.5v6A.5.5,0,0,1,25.5,22ZM18,17h7V15.651L23.232,13H19.768L18,15.651Z" style="fill:#009688"/><path d="M11.964,29.314a.5.5,0,0,0-.65-.278L7.152,30.7a17.321,17.321,0,0,1,3.739-6.888.5.5,0,1,0-.782-.624A19.312,19.312,0,0,0,6.359,29.8L4.964,26.314a.5.5,0,1,0-.928.372l2,5c0,.01.016.015.021.025a.475.475,0,0,0,.15.185c.009.007.016.017.025.023a.5.5,0,0,0,.2.076A.367.367,0,0,0,6.5,32h0a.475.475,0,0,0,.181-.036h0l5-2A.5.5,0,0,0,11.964,29.314Z" style="fill:#009688"/><rect x="4" y="34" width="31" height="1" style="fill:#009688"/><path d="M34.854,17.146l-13-13a.5.5,0,0,0-.708,0l-13,13a.5.5,0,0,0,.708.708L21.5,5.207,33.793,17.5,21.146,30.146a.5.5,0,0,0,.708.708l13-13A.5.5,0,0,0,34.854,17.146Z" style="fill:#b6b6b6"/><path d="M21.5,31a.5.5,0,0,1-.354-.146l-13-13a.5.5,0,0,1,.708-.708l13,13A.5.5,0,0,1,21.5,31Z" style="fill:#009688"/></svg>'), hr = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><path d="M27.878,34.926h-4.4c-.509,0-.845,0-.955-.394a.593.593,0,0,1,.36-.67,2.3,2.3,0,0,0,1.2-2.189,3.253,3.253,0,1,1,3.8,3.206Zm-3.538-1h2.988a2.253,2.253,0,1,0-2.253-2.253A3.445,3.445,0,0,1,24.34,33.926Z" style="fill:#009688"/><path d="M30.5,30.289l-.846-.535,4.364-6.9a.222.222,0,0,0-.36-.258l-5.4,6.644-.776-.631,5.4-6.644a1.222,1.222,0,0,1,1.982,1.423Z" style="fill:#009688"/><path d="M33.5,35h-1a.5.5,0,0,1,0-1h1a.5.5,0,0,0,.5-.5v-5a.5.5,0,0,1,1,0v5A1.5,1.5,0,0,1,33.5,35Z" style="fill:#b6b6b6"/><path d="M7.5,35a.5.5,0,0,1-.5-.5v-20a.5.5,0,0,1,1,0v20A.5.5,0,0,1,7.5,35Z" style="fill:#009688"/><path d="M10.5,35a.5.5,0,0,1-.5-.5v-20a.5.5,0,0,1,1,0v20A.5.5,0,0,1,10.5,35Z" style="fill:#009688"/><path d="M13.5,35h-9a.5.5,0,0,1-.5-.5v-20a.5.5,0,0,1,.5-.5h9a.5.5,0,0,1,.5.5v20A.5.5,0,0,1,13.5,35ZM5,34h8V15H5Z" style="fill:#009688"/><path d="M22.5,29a.5.5,0,0,1-.5-.5V15H4.5a.5.5,0,0,1-.5-.5v-9A1.5,1.5,0,0,1,5.5,4h28A1.5,1.5,0,0,1,35,5.5v13a.5.5,0,0,1-1,0V5.5a.5.5,0,0,0-.5-.5H5.5a.5.5,0,0,0-.5.5V14H22.5a.5.5,0,0,1,.5.5v14A.5.5,0,0,1,22.5,29Z" style="fill:#b6b6b6"/></svg>'), gr = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><path d="M24.5,26h-10A1.5,1.5,0,0,1,13,24.5v-10A1.5,1.5,0,0,1,14.5,13h10A1.5,1.5,0,0,1,26,14.5v10A1.5,1.5,0,0,1,24.5,26Zm-10-12a.5.5,0,0,0-.5.5v10a.5.5,0,0,0,.5.5h10a.5.5,0,0,0,.5-.5v-10a.5.5,0,0,0-.5-.5Z" style="fill:#b6b6b6"/><path d="M35,19.5A15.517,15.517,0,0,1,19.5,35a15.767,15.767,0,0,1-2.063-.136.5.5,0,0,1-.43-.562.507.507,0,0,1,.562-.43A14.5,14.5,0,1,0,19.5,5,14.43,14.43,0,0,0,7.751,11H11.5a.5.5,0,0,1,0,1h-5a.5.5,0,0,1-.5-.5v-5a.5.5,0,0,1,1,0v3.836A15.5,15.5,0,0,1,35,19.5ZM5.943,24.66a.5.5,0,1,0-.933.356A15.426,15.426,0,0,0,7.354,29.13a.5.5,0,0,0,.783-.621A14.533,14.533,0,0,1,5.943,24.66Zm8.4,8.4a14.523,14.523,0,0,1-3.85-2.194.5.5,0,0,0-.621.784,15.455,15.455,0,0,0,4.115,2.343.487.487,0,0,0,.178.033.5.5,0,0,0,.178-.966ZM5.128,21.431A14.621,14.621,0,0,1,5,19.5a.5.5,0,0,0-1,0,15.729,15.729,0,0,0,.136,2.062.5.5,0,0,0,.992-.131Z" style="fill:#009688"/></svg>'), br = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><path d="M25.5,5h-2a.5.5,0,0,1,0-1h2a.5.5,0,0,1,0,1ZM21,4.5a.5.5,0,0,0-.5-.5h-2a.5.5,0,0,0,0,1h2A.5.5,0,0,0,21,4.5Zm-5,0a.5.5,0,0,0-.5-.5h-2a.5.5,0,0,0,0,1h2A.5.5,0,0,0,16,4.5Zm10,30a.5.5,0,0,0-.5-.5h-2a.5.5,0,0,0,0,1h2A.5.5,0,0,0,26,34.5Zm-5,0a.5.5,0,0,0-.5-.5h-2a.5.5,0,0,0,0,1h2A.5.5,0,0,0,21,34.5Zm-5,0a.5.5,0,0,0-.5-.5h-2a.5.5,0,0,0,0,1h2A.5.5,0,0,0,16,34.5ZM5,15.5v-2a.5.5,0,0,0-1,0v2a.5.5,0,0,0,1,0Zm0,5v-2a.5.5,0,0,0-1,0v2a.5.5,0,0,0,1,0Zm0,5v-2a.5.5,0,0,0-1,0v2a.5.5,0,0,0,1,0Zm30-10v-2a.5.5,0,0,0-1,0v2a.5.5,0,0,0,1,0Zm0,5v-2a.5.5,0,0,0-1,0v2a.5.5,0,0,0,1,0Zm0,5v-2a.5.5,0,0,0-1,0v2a.5.5,0,0,0,1,0Zm-9-1v-10A1.5,1.5,0,0,0,24.5,13h-10A1.5,1.5,0,0,0,13,14.5v10A1.5,1.5,0,0,0,14.5,26h10A1.5,1.5,0,0,0,26,24.5ZM24.5,14a.5.5,0,0,1,.5.5v10a.5.5,0,0,1-.5.5h-10a.5.5,0,0,1-.5-.5v-10a.5.5,0,0,1,.5-.5Z" style="fill:#b6b6b6"/><path d="M34.962,4.309A.5.5,0,0,0,34.5,4h-5a.5.5,0,0,0,0,1h3.793l-6.147,6.146a.5.5,0,0,0,.708.708L34,5.707V9.5a.5.5,0,0,0,1,0v-5A.5.5,0,0,0,34.962,4.309Z" style="fill:#009688"/><path d="M5.707,5H9.5a.5.5,0,0,0,0-1h-5a.5.5,0,0,0-.5.5v5a.5.5,0,0,0,1,0V5.707l6.146,6.147a.5.5,0,0,0,.708-.708Z" style="fill:#009688"/><path d="M34.5,29a.5.5,0,0,0-.5.5v3.793l-6.146-6.147a.5.5,0,0,0-.708.708L33.293,34H29.5a.5.5,0,0,0,0,1h5a.5.5,0,0,0,.5-.5v-5A.5.5,0,0,0,34.5,29Z" style="fill:#009688"/><path d="M11.146,27.146,5,33.293V29.5a.5.5,0,0,0-1,0v5a.5.5,0,0,0,.5.5h5a.5.5,0,0,0,0-1H5.707l6.147-6.146a.5.5,0,0,0-.708-.708Z" style="fill:#009688"/></svg>'), xr = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M.5,13.5V1.5a1,1,0,0,1,1-1h12a1,1,0,0,1,1,1v12a1,1,0,0,1-1,1H1.5A1,1,0,0,1,.5,13.5Z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M8,3.5v2m0,2v2m0,2v2" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), Gt = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M.5,13.5V1.5a1,1,0,0,1,1-1h12a1,1,0,0,1,1,1v12a1,1,0,0,1-1,1H1.5A1,1,0,0,1,.5,13.5Z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M8,3.5v9" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M6,6.5,4,8l2,1.5" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M10,6.5,12,8l-2,1.5" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), yr = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M.5,13.5V1.5a1,1,0,0,1,1-1h12a1,1,0,0,1,1,1v12a1,1,0,0,1-1,1H1.5A1,1,0,0,1,.5,13.5Z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M4.5,5h7" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M8,5v6.5" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), vr = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M3,4.5h10" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M3,7h10" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M3,9h10" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M3,10.5h10" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M3,11.6h10" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>');
|
|
26
|
-
function
|
|
23
|
+
const Na = ':host{display:contents}*{box-sizing:border-box}.app-shell{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;flex-direction:column;background:#0e1216;color:#cdd6dd;font:14px/1.5 -apple-system,Segoe UI,sans-serif}.app-body{flex:1 1 auto;display:flex;min-height:0}.topbar{flex:0 0 44px;height:44px;display:flex;align-items:center;padding:0 12px;gap:10px;background:#161b21;border-bottom:1px solid #262d35}.topbar .tb-left,.topbar .tb-right{flex:1 1 0;display:flex;align-items:center;gap:8px}.topbar .tb-right{justify-content:flex-end}.tb-logo{font-size:15px;color:#e6edf3;letter-spacing:.01em}.tb-logo b{color:#00ae42}.tb-re{font-size:10px;background:#00ae42;color:#fff;padding:1px 5px;border-radius:4px;margin-left:2px}.tb-btn{display:inline-flex;align-items:center;gap:5px;background:#20272f;border:1px solid #2c353d;color:#cdd6dd;border-radius:6px;padding:4px 10px;cursor:pointer;font-size:12px}.tb-btn img{width:15px;height:15px}.tb-btn:hover{background:#28313a}.tb-tabs{display:flex;border:1px solid #2c353d;border-radius:8px;overflow:hidden;flex:0 0 auto}.tb-tabs button{padding:6px 24px;border:0;background:#1a2027;color:#9fb3c0;font-weight:600;font-size:13px;cursor:pointer}.tb-tabs button.on{background:#00ae42;color:#fff}.tb-tabs button:disabled{color:#5a6570;cursor:not-allowed}.tb-icon{width:28px;height:28px;border:1px solid #2c353d;background:#20272f;color:#7d8b96;border-radius:6px;font-size:15px;cursor:not-allowed}.left-rail{flex:0 0 48px;display:flex;flex-direction:column;align-items:center;gap:6px;padding:9px 0;background:#12171c;border-right:1px solid #232a31}.left-rail button{width:36px;height:36px;border:1px solid transparent;border-radius:8px;background:transparent;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0}.left-rail button img{width:21px;height:21px;opacity:.72}.left-rail button:hover{background:#1e252c}.left-rail button.on{background:#00ae42}.left-rail button.on img{opacity:1;filter:brightness(1.6)}.rail-sep{width:26px;height:1px;background:#2a323a;margin:3px 0}.viewport-col{position:relative;flex:1 1 auto;min-width:0;background:#161a1e}.vp-top-toolbar{position:absolute;top:12px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:3px;background:#12171cd9;padding:4px;border-radius:9px;border:1px solid #2a323a;z-index:3;max-width:calc(100% - 24px);overflow-x:auto;scrollbar-width:none}.vp-top-toolbar::-webkit-scrollbar{display:none}.vp-top-toolbar>*{flex:0 0 auto}.vp-top-toolbar button{width:32px;height:32px;border:0;background:transparent;border-radius:6px;cursor:pointer;display:flex;align-items:center;justify-content:center}.vp-top-toolbar button img{width:18px;height:18px;opacity:.82}.vp-top-toolbar button:hover:not(:disabled){background:#2a333c}.vp-top-toolbar button:disabled{opacity:.32;cursor:not-allowed}.vtt-sep{width:1px;align-self:stretch;background:#333c45;margin:3px}.plate-bar{position:absolute;right:14px;bottom:30px;display:flex;align-items:center;gap:4px;z-index:3;background:#12171cd9;border:1px solid #2a323a;border-radius:9px;padding:4px}.plate-bar button{min-width:26px;height:26px;border:1px solid #2c353d;background:#1a2027;color:#9fb3c0;border-radius:6px;cursor:pointer;font-size:12px;font-weight:600}.plate-tab.on{background:#00ae42;color:#fff;border-color:#00ae42}.plate-add{color:#7ad19a!important}.plate-del{color:#e08a8a!important}.plate-bar button:disabled{opacity:.4;cursor:not-allowed}.slice-dd{position:relative;flex:1.4}.slice-dd .slice-btn{width:100%}.slice-menu{position:absolute;bottom:calc(100% + 6px);left:0;right:0;background:#fff;border:1px solid #d5d8dd;border-radius:8px;box-shadow:0 4px 16px #0000002e;overflow:hidden;z-index:10}.slice-menu button{display:block;width:100%;text-align:left;padding:9px 12px;border:0;background:#fff;color:#24282e;cursor:pointer;font-size:13px}.slice-menu button:hover{background:#eef7f1}.brush-panel{position:absolute;top:58px;left:14px;width:214px;background:#161b21f2;border:1px solid #2c353d;border-radius:10px;padding:10px;z-index:4;box-shadow:0 3px 14px #00000073}.bp-title{font-weight:600;margin-bottom:6px;color:#cdd6dd}.bp-modes{display:flex;gap:4px;flex-wrap:wrap}.bp-modes button{padding:3px 9px;border:1px solid #2c353d;background:#1a2027;color:#cdd6dd;border-radius:5px;cursor:pointer;font-size:12px}.bp-modes button.enf.on{background:#2b6cff;color:#fff;border-color:#2b6cff}.bp-modes button.blk.on{background:#e23b3b;color:#fff;border-color:#e23b3b}.bp-tools{margin-top:6px}.bp-tool.on{background:#2c353d;color:#fff;border-color:#46525c}.bp-radius{display:block;font-size:12px;color:#aebcc6;margin-top:8px}.bp-radius input{width:100%}.bp-counts{margin-top:6px;font-size:11px}.bp-chip{min-width:30px;font-weight:700;border-color:#00000059!important}.bp-chip.on{outline:2px solid #fff;outline-offset:1px}.bp-eraser{background:#1a2027!important;color:#cdd6dd!important;font-weight:400}.bp-actions{margin-top:6px}.bp-note{margin-top:6px;font-size:10.5px;line-height:1.35;color:#8b98a2}.stats-card{position:absolute;left:14px;bottom:32px;background:#161b21ed;border:1px solid #2c353d;border-radius:10px;padding:10px 14px;font-size:13px;line-height:1.7;z-index:2;color:#cdd6dd}.stats-card b{color:#9fe3bd}.stat-tool{display:flex;align-items:center;gap:5px;font-size:12px;margin-left:10px}.stat-swatch{width:9px;height:9px;border-radius:2px;border:1px solid rgba(255,255,255,.28);flex:0 0 auto}.stat-swatch-purge{background:repeating-linear-gradient(45deg,#6d7780 0,#6d7780 2px,#39424a 2px,#39424a 4px)}.sidebar{flex:0 0 384px;width:384px;display:flex;flex-direction:column;background:#eef0f2;color:#24282e;border-left:1px solid #d5d8dd;min-height:0}.sidebar-scroll{flex:1 1 auto;overflow-y:auto;padding:10px;display:flex;flex-direction:column;gap:10px}.side-card{background:#fff;border:1px solid #e2e4e8;border-radius:10px;padding:10px 12px}.sc-head{font-weight:700;font-size:13px;color:#2a2f36;display:flex;align-items:center;gap:6px;margin-bottom:7px}.sc-count{background:#00ae42;color:#fff;font-size:10px;border-radius:8px;padding:0 6px;font-weight:700}.sc-head-btns{margin-left:auto;display:flex;gap:4px}.sc-head-btns button{width:22px;height:22px;border:1px solid #d3d6db;background:#f6f7f8;border-radius:5px;cursor:pointer;font-size:14px;line-height:1;color:#333}.sc-head-btns button:disabled{opacity:.4;cursor:not-allowed}.sc-preset-btns button{width:auto;padding:0 8px;font-size:11px;white-space:nowrap}.sc-dirty{color:#c47f00;font-weight:600}.sc-info{display:flex;justify-content:space-between;font-size:12px;color:#5a6069;padding:2px 0}.sc-info b{color:#24282e}.side-warn{margin:0 2px;font-size:12px}.filament-row{display:flex;align-items:center;gap:8px;padding:3px 0}.filament-row input[type=color]{width:28px;height:22px;border:1px solid #ccc;border-radius:5px;padding:0;cursor:pointer;background:none}.filament-row{cursor:pointer;border-radius:5px;padding-left:4px}.filament-row.fil-active{background:#eef6f0;box-shadow:inset 2px 0 #00ae42}.fil-mat{font-size:11.5px;color:#5a6069;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-note{color:#8a9099;font-size:11px;font-style:italic}.fil-t{font-weight:700;font-size:12px;width:20px}.fil-mat{flex:1;min-width:0}.fil-badge{font-size:9.5px;font-weight:700;text-transform:uppercase;letter-spacing:.3px;color:#5a6069;background:#eceef1;border-radius:7px;padding:1px 5px;white-space:nowrap}.fil-count{font-size:10px;font-weight:700;color:#fff;background:#2b6cff;border-radius:7px;padding:0 5px}.fil-paint{border:1px solid #d3d6db;background:#f6f7f8;border-radius:5px;cursor:pointer;font-size:11px;line-height:1;padding:3px 5px}.fil-paint.on{background:#2b6cff;border-color:#2b6cff}.obj-list2{list-style:none;margin:0 0 6px;padding:0}.obj-list2 li{display:flex;align-items:center;gap:6px;padding:3px 0;font-size:12px}.obj-list2 li.obj-hidden{opacity:.5}.obj-eye{border:0;background:none;cursor:pointer;font-size:13px;padding:0}.obj-list2 .obj-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#24282e}.obj-list2 .obj-ext{border:1px solid #d0d3d8;border-radius:5px;font-size:11px;padding:1px 3px;background:#fff}.obj-del{border:0;background:#fbe9ec;color:#d0435a;border-radius:5px;cursor:pointer;padding:0 6px}.obj-painted{font-size:10px;line-height:1;background:#e6efff;border-radius:6px;padding:2px 4px}.side-card .slice-support{color:#444;font-size:12px;margin:5px 0 0}.process-card{padding:8px}.side-card .view-type-row{color:#444}.side-card .view-type-row select,.side-card .obj-ext{background:#fff;color:#222;border:1px solid #ccd0d5}.side-card .slice-layer label{color:#444;font-size:12px}.side-card .grad-title{color:#333}.side-card .grad-minmax{color:#666}.side-card .role-legend,.side-card .slice-travel{color:#555}.side-card .layer-ctl button{background:#f1f2f4;color:#333;border:1px solid #d3d6db}.side-card .layer-ctl button.on{background:#00ae42;color:#fff;border-color:#00ae42}.side-bottom{flex:0 0 auto;display:flex;gap:8px;padding:10px;border-top:1px solid #dcdfe3;background:#e6e9ec}.side-bottom .slice-btn{flex:1.4;margin:0}.auto-slice{display:flex;align-items:center;gap:5px;font-size:12px;color:#444;cursor:pointer;white-space:nowrap;-webkit-user-select:none;user-select:none}.auto-slice input{margin:0}.export-btn{flex:1;text-align:center;padding:9px;border-radius:8px;background:#dfe6ea;color:#1f6feb;border:1px solid #c7d2da;text-decoration:none;font-weight:600;cursor:pointer;font-size:13px}.export-btn:hover{background:#d3dee4}.export-btn:disabled{color:#9aa4ad;background:#e9ecef;cursor:not-allowed}.vp-canvas{position:absolute;top:0;right:0;bottom:0;left:0}.vp-canvas canvas{display:block}.vp-canvas.fail{display:flex;align-items:center;justify-content:center}.vp-fallback{color:#f0c9a8;padding:24px;text-align:center;max-width:560px;line-height:1.5}.vp-status{position:absolute;bottom:8px;left:12px;right:12px;z-index:1;font-size:11.5px;color:#9fe3bd;font-family:ui-monospace,monospace;text-shadow:0 1px 2px #000;pointer-events:none}.slice-warn{color:#f0c060;margin:4px 0}.sc-sub{font-size:10.5px;opacity:.62;margin:1px 0 3px}.sc-fold>summary{display:flex;justify-content:space-between;align-items:center;font-size:12px;color:#5a6069;padding:2px 0;cursor:pointer;list-style:none}.sc-fold>summary::-webkit-details-marker{display:none}.sc-fold-lbl:before{content:"▸";display:inline-block;width:10px;font-size:9px;opacity:.5}.sc-fold[open] .sc-fold-lbl:before{content:"▾"}.sc-fold>summary b{color:#24282e}.sc-fold[open]>summary{border-bottom:1px solid #e3e6ea;margin-bottom:4px}.sc-fold-body{max-height:320px;overflow-y:auto}.sc-model{max-width:62%;font-size:11.5px;padding:1px 2px}.support-tools{display:flex;align-items:center;justify-content:space-between;gap:8px;margin:2px 0 2px 16px;padding-left:6px;border-left:2px solid #e3e6ea}.sup-style{margin-left:16px;padding-left:6px;border-left:2px solid #e3e6ea}.sup-paint{font-size:11px;padding:2px 8px;border:1px solid #c9ced6;border-radius:5px;background:#fff;color:#24282e;cursor:pointer;white-space:nowrap}.sup-paint.on{background:#2b6cff;border-color:#2b6cff;color:#fff}.sup-paint:disabled{opacity:.45;cursor:not-allowed}.sup-filament-warn{margin:2px 0 2px 22px;font-size:11px;line-height:1.35;color:#a06a00}.slice-btn{width:100%;margin-top:6px;padding:7px;border:0;border-radius:7px;background:#00ae42;color:#fff;font-weight:700;cursor:pointer}.slice-btn:disabled{background:#3a4650;color:#8b98a2;cursor:not-allowed}.slice-err{color:#ff8b8b;margin-top:6px}.slice-stats{margin-top:8px;line-height:1.5}.slice-stats b{color:#9fe3bd}.slice-layer{margin-top:8px;display:flex;flex-direction:column;gap:4px}.slice-layer input[type=range]{width:100%}.slice-travel{color:#aebcc6;display:flex;align-items:center;gap:4px}.view-type-row{display:flex;align-items:center;justify-content:space-between;gap:6px;color:#aebcc6}.view-type-row select{flex:1;background:#10141a;color:#eee;border:1px solid #2c353d;border-radius:4px;padding:2px 4px}.dual-slider{position:relative;height:22px}.dual-slider input[type=range]{position:absolute;left:0;top:0;width:100%;margin:0;pointer-events:none;background:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.dual-slider input[type=range]::-webkit-slider-thumb{pointer-events:auto;-webkit-appearance:none;width:13px;height:13px;border-radius:50%;background:#00ae42;border:2px solid #0c1013;cursor:pointer}.dual-slider input[type=range]::-moz-range-thumb{pointer-events:auto;width:13px;height:13px;border-radius:50%;background:#00ae42;border:2px solid #0c1013;cursor:pointer}.dual-slider input[type=range]::-webkit-slider-runnable-track{height:4px;background:#2c353d;border-radius:2px}.dual-slider input[type=range]:first-child{z-index:2}.layer-ctl{display:flex;align-items:center;gap:8px}.layer-ctl button{padding:2px 8px;border:1px solid #2c353d;border-radius:5px;background:#1a2027;color:#cdd6dd;font-size:11px;cursor:pointer}.layer-ctl button.on{background:#00ae42;color:#fff;border-color:#00ae42}.grad-legend{margin-top:6px}.grad-title{font-size:11px;color:#cdd6dd;margin-bottom:3px}.grad-bar{height:10px;border-radius:3px;border:1px solid #2c353d}.grad-minmax{display:flex;justify-content:space-between;font-size:10px;color:#aebcc6;margin-top:2px}.role-legend{display:flex;flex-wrap:wrap;gap:4px 10px;margin-top:6px;font-size:11px;color:#aebcc6}.role-item{display:inline-flex;align-items:center;gap:4px}.role-item i{width:10px;height:6px;border-radius:2px;display:inline-block}.role-item b{color:#cdd6dd}.vp-canvas.drag-over{outline:3px dashed #00ae42;outline-offset:-6px}.empty-hint{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;pointer-events:none;color:#9fb3c0;text-align:center}.empty-hint .eh-icon{font-size:46px;opacity:.8}.empty-hint .eh-title{font-size:16px;font-weight:600;color:#cdd6dd}.empty-hint .eh-sub{font-size:12px;color:#7d8b96;letter-spacing:.04em}.empty-hint .eh-btn{pointer-events:auto;margin-top:8px;padding:7px 18px;border:0;border-radius:7px;background:#00ae42;color:#fff;font-weight:600;cursor:pointer}.empty-hint .eh-btn:hover{background:#06c04d}.drop-overlay{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;background:#00ae4224;color:#d7f7e3;font-size:18px;font-weight:700;pointer-events:none;border:3px dashed #00ae42;box-sizing:border-box}.obj-split{border:0;background:transparent;cursor:pointer;padding:0 3px;line-height:0}.obj-split img{width:13px;height:13px;opacity:.6}.obj-split:hover img{opacity:1}.ctx-scrim{position:absolute;top:0;right:0;bottom:0;left:0;z-index:24}.ctx-menu{position:absolute;z-index:25;min-width:168px;padding:4px;background:#1b2027;border:1px solid #2f3944;border-radius:8px;box-shadow:0 8px 24px #00000080}.ctx-menu button{display:flex;width:100%;align-items:center;justify-content:space-between;gap:16px;padding:6px 10px;border:0;border-radius:5px;background:transparent;color:#dfe6ee;font-size:12px;text-align:left;cursor:pointer}.ctx-menu button:hover:not(:disabled){background:#273140}.ctx-menu button:disabled{color:#64707d;cursor:not-allowed}.ctx-menu button.danger:hover:not(:disabled){background:#4a2229;color:#ffb3b3}.ctx-menu hr{margin:4px 6px;border:0;border-top:1px solid #2f3944}.ctx-key{color:#7d8b96;font-family:ui-monospace,monospace;font-size:11px}.help-overlay{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;background:#080c10b8;z-index:20}.help-card{background:#1b2027;color:#dfe6ee;border:1px solid #2f3944;border-radius:10px;padding:18px 22px;max-width:720px;box-shadow:0 12px 40px #00000080}.help-card h3{margin:0 0 12px;font-size:15px}.help-card h4{margin:0 0 6px;font-size:12px;color:#00ae42;text-transform:uppercase;letter-spacing:.04em}.help-cols{display:flex;gap:26px;flex-wrap:wrap}.help-card dl{display:grid;grid-template-columns:auto 1fr;gap:3px 12px;margin:0;font-size:12px}.help-card dt{color:#9fb0c2;font-family:ui-monospace,monospace;white-space:nowrap}.help-card dd{margin:0}.slice-support{display:flex;align-items:center;gap:5px;margin:6px 0;color:#cdd6dd;font-size:12px}.slice-support .muted{font-size:10px}.sc-bed{display:inline-flex;align-items:center;gap:4px;font-weight:700;color:#222}.sc-bed input{width:54px;padding:1px 4px;font-size:12px;font-weight:600;text-align:right;border:1px solid #ccd0d5;border-radius:5px;background:#fff;color:#222}.stat-split{color:#8b98a2;font-size:11px}.stat-type{margin-left:4px;padding:0 4px;border-radius:3px;background:#2c353d;color:#aebcc6;font-size:10.5px}.purge-grid{width:100%;border-collapse:collapse;font-size:11px}.purge-grid th{font-weight:600;color:#aebcc6;padding:2px 3px;white-space:nowrap}.purge-grid th .stat-swatch{margin-right:3px;vertical-align:middle}.purge-grid td{padding:1px 2px;text-align:center}.purge-grid input{width:100%;min-width:42px;background:#1a2027;border:1px solid #2c353d;color:#cdd6dd;border-radius:4px;padding:2px 3px;font-size:11px}.sc-num input{width:62px;background:#1a2027;border:1px solid #2c353d;color:#cdd6dd;border-radius:4px;padding:2px 5px;font-size:12px;margin-left:4px}', Ma = 40, rt = (t) => t + Ma, tr = 9, Ft = (t) => {
|
|
24
|
+
const r = Math.sqrt(t), c = Math.round(r);
|
|
25
|
+
return r > c ? c + 1 : c;
|
|
26
|
+
}, Aa = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M.5,13.5V1.5a1,1,0,0,1,1-1h12a1,1,0,0,1,1,1v12a1,1,0,0,1-1,1H1.5A1,1,0,0,1,.5,13.5Zm3-6h3m2,0h3m-4-4v8" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), Ca = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><path d="M33.5,35H5.5A1.5,1.5,0,0,1,4,33.5V5.5A1.5,1.5,0,0,1,5.5,4h28A1.5,1.5,0,0,1,35,5.5v28A1.5,1.5,0,0,1,33.5,35ZM5.5,5a.5.5,0,0,0-.5.5v28a.5.5,0,0,0,.5.5h28a.5.5,0,0,0,.5-.5V5.5a.5.5,0,0,0-.5-.5Z" style="fill:#b6b6b6"/><path d="M30.5,32H8.5A1.5,1.5,0,0,1,7,30.5v-6A1.5,1.5,0,0,1,8.5,23h22A1.5,1.5,0,0,1,32,24.5v6A1.5,1.5,0,0,1,30.5,32Zm-22-8a.5.5,0,0,0-.5.5v6a.5.5,0,0,0,.5.5h22a.5.5,0,0,0,.5-.5v-6a.5.5,0,0,0-.5-.5Zm22-2h-6A1.5,1.5,0,0,1,23,20.5V8.5A1.5,1.5,0,0,1,24.5,7h6A1.5,1.5,0,0,1,32,8.5v12A1.5,1.5,0,0,1,30.5,22Zm-6-14a.5.5,0,0,0-.5.5v12a.5.5,0,0,0,.5.5h6a.5.5,0,0,0,.5-.5V8.5a.5.5,0,0,0-.5-.5Zm-6,6h-8a3.5,3.5,0,0,1,0-7h8a3.5,3.5,0,0,1,0,7Zm-8-6a2.5,2.5,0,0,0,0,5h8a2.5,2.5,0,0,0,0-5Zm8,14A3.5,3.5,0,1,1,22,18.5,3.5,3.5,0,0,1,18.5,22Zm0-6A2.5,2.5,0,1,0,21,18.5,2.5,2.5,0,0,0,18.5,16Zm-8,6A3.5,3.5,0,1,1,14,18.5,3.5,3.5,0,0,1,10.5,22Zm0-6A2.5,2.5,0,1,0,13,18.5,2.5,2.5,0,0,0,10.5,16Z" style="fill:#009688"/></svg>'), ja = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M6.2,8a2.6,2.6,0,1,0,5.2,0a2.6,2.6,0,1,0,-5.2,0" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M4.6,8a2.6,2.6,0,1,0,5.2,0a2.6,2.6,0,1,0,-5.2,0" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), Pa = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M.5,13.5V1.5a1,1,0,0,1,1-1h12a1,1,0,0,1,1,1v12a1,1,0,0,1-1,1H1.5A1,1,0,0,1,.5,13.5Z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M3.5,9h2m2,0h2m2,0h2" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M8,3.5l1.8,3h-3.6z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), nr = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M.5,13.5V1.5a1,1,0,0,1,1-1h12a1,1,0,0,1,1,1v12a1,1,0,0,1-1,1H1.5A1,1,0,0,1,.5,13.5Zm3-6h8" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), za = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M.5,13.5V1.5a1,1,0,0,1,1-1h12a1,1,0,0,1,1,1v12a1,1,0,0,1-1,1H1.5A1,1,0,0,1,.5,13.5Z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M5,5l6,6" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M11,5l-6,6" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), Ra = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M4,4h5v5H4z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M7,7h5v5H7z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), Ta = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M8,3a5.93,5.93,0,0,0-4.95,2.5A9.1,9.1,0,0,0,1,8a9.1,9.1,0,0,0,2.05,2.5A5.93,5.93,0,0,0,8,13a5.93,5.93,0,0,0,4.95-2.5A9.1,9.1,0,0,0,15,8a9.1,9.1,0,0,0-2.05-2.5A5.93,5.93,0,0,0,8,3m0,8a2,2,0,1,1,2-2A2,2,0,0,1,8,11" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), Oa = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M1.5,2.5l13,11" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M8,3a5.93,5.93,0,0,0-4.95,2.5A9.1,9.1,0,0,0,1,8a9.1,9.1,0,0,0,2.05,2.5" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M8,3a5.93,5.93,0,0,1,4.95,2.5A9.1,9.1,0,0,1,15,8a9.1,9.1,0,0,1-2.05,2.5" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><circle cx="8" cy="8" r="2" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), La = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M2.5,8h11" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M2.5,6v4" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M13.5,6v4" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M6,7v2" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M10,7v2" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), Sa = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M4,8a4,4,0,1,0,8,0a4,4,0,1,0,-8,0" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M8,4a4,4,0,0,1,0,8z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1;fill:#949494;stroke:none"/></svg>'), Fa = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><path d="M34.854,19.146l-4-4a.5.5,0,0,0-.708.708L33.293,19H28.5a.5.5,0,0,0,0,1h4.793l-3.147,3.146a.5.5,0,0,0,.708.708l4-4A.5.5,0,0,0,34.854,19.146Z" style="fill:#009688"/><path d="M19.854,4.146a.5.5,0,0,0-.708,0l-4,4a.5.5,0,0,0,.708.708L19,5.707V10.5a.5.5,0,0,0,1,0V5.707l3.146,3.147a.5.5,0,0,0,.708-.708Z" style="fill:#009688"/><path d="M23.146,30.146,20,33.293V28.5a.5.5,0,0,0-1,0v4.793l-3.146-3.147a.5.5,0,0,0-.708.708l4,4a.5.5,0,0,0,.708,0l4-4a.5.5,0,0,0-.708-.708Z" style="fill:#009688"/><path d="M10.5,19H5.707l3.147-3.146a.5.5,0,0,0-.708-.708l-4,4a.5.5,0,0,0,0,.708l4,4a.5.5,0,0,0,.708-.708L5.707,20H10.5a.5.5,0,0,0,0-1Z" style="fill:#009688"/><path d="M24.5,26h-10A1.5,1.5,0,0,1,13,24.5v-10A1.5,1.5,0,0,1,14.5,13h10A1.5,1.5,0,0,1,26,14.5v10A1.5,1.5,0,0,1,24.5,26Zm-10-12a.5.5,0,0,0-.5.5v10a.5.5,0,0,0,.5.5h10a.5.5,0,0,0,.5-.5v-10a.5.5,0,0,0-.5-.5Z" style="fill:#b6b6b6"/></svg>'), Ba = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M.5,13.5V1.5a1,1,0,0,1,1-1h12a1,1,0,0,1,1,1v12a1,1,0,0,1-1,1H1.5A1,1,0,0,1,.5,13.5Z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M5,5h6v6H5z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1;stroke-dasharray:2 1.5"/></svg>'), Da = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M.5,13.5V1.5a1,1,0,0,1,1-1h12a1,1,0,0,1,1,1v12a1,1,0,0,1-1,1H1.5A1,1,0,0,1,.5,13.5Z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M8,3.5v5m-2-2 2,2 2-2" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M4,11.5h8" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), $a = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><path d="M34.923,10.25a.392.392,0,0,0-.033-.05.5.5,0,0,0-.2-.162l0,0-15-6a.5.5,0,0,0-.372,0l-15,6,0,0a.5.5,0,0,0-.2.162.392.392,0,0,0-.033.05A.478.478,0,0,0,4,10.5v18a.464.464,0,0,0,.028.138.429.429,0,0,0,.011.054l.01.015a.51.51,0,0,0,.1.144l.008,0a.5.5,0,0,0,.156.1l0,0,14.989,6,0,0,.006,0a.5.5,0,0,0,.372,0l.006,0,0,0,1.989-.8a.5.5,0,0,0-.372-.928L20,33.762V16.839l14-5.6V21.5a.5.5,0,0,0,1,0v-11A.481.481,0,0,0,34.923,10.25ZM19,33.762l-14-5.6V11.239l14,5.6Zm.5-17.8L5.846,10.5,19.5,5.039,33.153,10.5Z" style="fill:#b6b6b6"/><path d="M33.5,24h-8A1.5,1.5,0,0,0,24,25.5v8A1.5,1.5,0,0,0,25.5,35h8A1.5,1.5,0,0,0,35,33.5v-8A1.5,1.5,0,0,0,33.5,24Zm.5,9.5a.5.5,0,0,1-.5.5h-8a.5.5,0,0,1-.5-.5v-8a.5.5,0,0,1,.5-.5h8a.5.5,0,0,1,.5.5Z" style="fill:#009688"/><path d="M32.5,29H30V26.5a.5.5,0,0,0-1,0V29H26.5a.5.5,0,0,0,0,1H29v2.5a.5.5,0,0,0,1,0V30h2.5a.5.5,0,0,0,0-1Z" style="fill:#009688"/></svg>'), Ia = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><path d="M25.5,22a.5.5,0,0,1-.5-.5V18H18v3.5a.5.5,0,0,1-1,0v-6a.5.5,0,0,1,.084-.277l2-3A.5.5,0,0,1,19.5,12h4a.5.5,0,0,1,.416.223l2,3A.5.5,0,0,1,26,15.5v6A.5.5,0,0,1,25.5,22ZM18,17h7V15.651L23.232,13H19.768L18,15.651Z" style="fill:#009688"/><path d="M11.964,29.314a.5.5,0,0,0-.65-.278L7.152,30.7a17.321,17.321,0,0,1,3.739-6.888.5.5,0,1,0-.782-.624A19.312,19.312,0,0,0,6.359,29.8L4.964,26.314a.5.5,0,1,0-.928.372l2,5c0,.01.016.015.021.025a.475.475,0,0,0,.15.185c.009.007.016.017.025.023a.5.5,0,0,0,.2.076A.367.367,0,0,0,6.5,32h0a.475.475,0,0,0,.181-.036h0l5-2A.5.5,0,0,0,11.964,29.314Z" style="fill:#009688"/><rect x="4" y="34" width="31" height="1" style="fill:#009688"/><path d="M34.854,17.146l-13-13a.5.5,0,0,0-.708,0l-13,13a.5.5,0,0,0,.708.708L21.5,5.207,33.793,17.5,21.146,30.146a.5.5,0,0,0,.708.708l13-13A.5.5,0,0,0,34.854,17.146Z" style="fill:#b6b6b6"/><path d="M21.5,31a.5.5,0,0,1-.354-.146l-13-13a.5.5,0,0,1,.708-.708l13,13A.5.5,0,0,1,21.5,31Z" style="fill:#009688"/></svg>'), Za = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><path d="M27.878,34.926h-4.4c-.509,0-.845,0-.955-.394a.593.593,0,0,1,.36-.67,2.3,2.3,0,0,0,1.2-2.189,3.253,3.253,0,1,1,3.8,3.206Zm-3.538-1h2.988a2.253,2.253,0,1,0-2.253-2.253A3.445,3.445,0,0,1,24.34,33.926Z" style="fill:#009688"/><path d="M30.5,30.289l-.846-.535,4.364-6.9a.222.222,0,0,0-.36-.258l-5.4,6.644-.776-.631,5.4-6.644a1.222,1.222,0,0,1,1.982,1.423Z" style="fill:#009688"/><path d="M33.5,35h-1a.5.5,0,0,1,0-1h1a.5.5,0,0,0,.5-.5v-5a.5.5,0,0,1,1,0v5A1.5,1.5,0,0,1,33.5,35Z" style="fill:#b6b6b6"/><path d="M7.5,35a.5.5,0,0,1-.5-.5v-20a.5.5,0,0,1,1,0v20A.5.5,0,0,1,7.5,35Z" style="fill:#009688"/><path d="M10.5,35a.5.5,0,0,1-.5-.5v-20a.5.5,0,0,1,1,0v20A.5.5,0,0,1,10.5,35Z" style="fill:#009688"/><path d="M13.5,35h-9a.5.5,0,0,1-.5-.5v-20a.5.5,0,0,1,.5-.5h9a.5.5,0,0,1,.5.5v20A.5.5,0,0,1,13.5,35ZM5,34h8V15H5Z" style="fill:#009688"/><path d="M22.5,29a.5.5,0,0,1-.5-.5V15H4.5a.5.5,0,0,1-.5-.5v-9A1.5,1.5,0,0,1,5.5,4h28A1.5,1.5,0,0,1,35,5.5v13a.5.5,0,0,1-1,0V5.5a.5.5,0,0,0-.5-.5H5.5a.5.5,0,0,0-.5.5V14H22.5a.5.5,0,0,1,.5.5v14A.5.5,0,0,1,22.5,29Z" style="fill:#b6b6b6"/></svg>'), Va = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><path d="M24.5,26h-10A1.5,1.5,0,0,1,13,24.5v-10A1.5,1.5,0,0,1,14.5,13h10A1.5,1.5,0,0,1,26,14.5v10A1.5,1.5,0,0,1,24.5,26Zm-10-12a.5.5,0,0,0-.5.5v10a.5.5,0,0,0,.5.5h10a.5.5,0,0,0,.5-.5v-10a.5.5,0,0,0-.5-.5Z" style="fill:#b6b6b6"/><path d="M35,19.5A15.517,15.517,0,0,1,19.5,35a15.767,15.767,0,0,1-2.063-.136.5.5,0,0,1-.43-.562.507.507,0,0,1,.562-.43A14.5,14.5,0,1,0,19.5,5,14.43,14.43,0,0,0,7.751,11H11.5a.5.5,0,0,1,0,1h-5a.5.5,0,0,1-.5-.5v-5a.5.5,0,0,1,1,0v3.836A15.5,15.5,0,0,1,35,19.5ZM5.943,24.66a.5.5,0,1,0-.933.356A15.426,15.426,0,0,0,7.354,29.13a.5.5,0,0,0,.783-.621A14.533,14.533,0,0,1,5.943,24.66Zm8.4,8.4a14.523,14.523,0,0,1-3.85-2.194.5.5,0,0,0-.621.784,15.455,15.455,0,0,0,4.115,2.343.487.487,0,0,0,.178.033.5.5,0,0,0,.178-.966ZM5.128,21.431A14.621,14.621,0,0,1,5,19.5a.5.5,0,0,0-1,0,15.729,15.729,0,0,0,.136,2.062.5.5,0,0,0,.992-.131Z" style="fill:#009688"/></svg>'), Ga = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><path d="M25.5,5h-2a.5.5,0,0,1,0-1h2a.5.5,0,0,1,0,1ZM21,4.5a.5.5,0,0,0-.5-.5h-2a.5.5,0,0,0,0,1h2A.5.5,0,0,0,21,4.5Zm-5,0a.5.5,0,0,0-.5-.5h-2a.5.5,0,0,0,0,1h2A.5.5,0,0,0,16,4.5Zm10,30a.5.5,0,0,0-.5-.5h-2a.5.5,0,0,0,0,1h2A.5.5,0,0,0,26,34.5Zm-5,0a.5.5,0,0,0-.5-.5h-2a.5.5,0,0,0,0,1h2A.5.5,0,0,0,21,34.5Zm-5,0a.5.5,0,0,0-.5-.5h-2a.5.5,0,0,0,0,1h2A.5.5,0,0,0,16,34.5ZM5,15.5v-2a.5.5,0,0,0-1,0v2a.5.5,0,0,0,1,0Zm0,5v-2a.5.5,0,0,0-1,0v2a.5.5,0,0,0,1,0Zm0,5v-2a.5.5,0,0,0-1,0v2a.5.5,0,0,0,1,0Zm30-10v-2a.5.5,0,0,0-1,0v2a.5.5,0,0,0,1,0Zm0,5v-2a.5.5,0,0,0-1,0v2a.5.5,0,0,0,1,0Zm0,5v-2a.5.5,0,0,0-1,0v2a.5.5,0,0,0,1,0Zm-9-1v-10A1.5,1.5,0,0,0,24.5,13h-10A1.5,1.5,0,0,0,13,14.5v10A1.5,1.5,0,0,0,14.5,26h10A1.5,1.5,0,0,0,26,24.5ZM24.5,14a.5.5,0,0,1,.5.5v10a.5.5,0,0,1-.5.5h-10a.5.5,0,0,1-.5-.5v-10a.5.5,0,0,1,.5-.5Z" style="fill:#b6b6b6"/><path d="M34.962,4.309A.5.5,0,0,0,34.5,4h-5a.5.5,0,0,0,0,1h3.793l-6.147,6.146a.5.5,0,0,0,.708.708L34,5.707V9.5a.5.5,0,0,0,1,0v-5A.5.5,0,0,0,34.962,4.309Z" style="fill:#009688"/><path d="M5.707,5H9.5a.5.5,0,0,0,0-1h-5a.5.5,0,0,0-.5.5v5a.5.5,0,0,0,1,0V5.707l6.146,6.147a.5.5,0,0,0,.708-.708Z" style="fill:#009688"/><path d="M34.5,29a.5.5,0,0,0-.5.5v3.793l-6.146-6.147a.5.5,0,0,0-.708.708L33.293,34H29.5a.5.5,0,0,0,0,1h5a.5.5,0,0,0,.5-.5v-5A.5.5,0,0,0,34.5,29Z" style="fill:#009688"/><path d="M11.146,27.146,5,33.293V29.5a.5.5,0,0,0-1,0v5a.5.5,0,0,0,.5.5h5a.5.5,0,0,0,0-1H5.707l6.147-6.146a.5.5,0,0,0-.708-.708Z" style="fill:#009688"/></svg>'), Ua = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M.5,13.5V1.5a1,1,0,0,1,1-1h12a1,1,0,0,1,1,1v12a1,1,0,0,1-1,1H1.5A1,1,0,0,1,.5,13.5Z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M8,3.5v2m0,2v2m0,2v2" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), rr = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M.5,13.5V1.5a1,1,0,0,1,1-1h12a1,1,0,0,1,1,1v12a1,1,0,0,1-1,1H1.5A1,1,0,0,1,.5,13.5Z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M8,3.5v9" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M6,6.5,4,8l2,1.5" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M10,6.5,12,8l-2,1.5" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), Wa = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M.5,13.5V1.5a1,1,0,0,1,1-1h12a1,1,0,0,1,1,1v12a1,1,0,0,1-1,1H1.5A1,1,0,0,1,.5,13.5Z" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M4.5,5h7" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M8,5v6.5" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>'), Ha = "data:image/svg+xml;utf8," + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M3,4.5h10" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M3,7h10" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M3,9h10" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M3,10.5h10" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/><path d="M3,11.6h10" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round;opacity:1"/></svg>');
|
|
27
|
+
function qa(t) {
|
|
27
28
|
return [
|
|
28
|
-
{ id: "add", icon:
|
|
29
|
-
{ id: "delete", icon:
|
|
30
|
-
{ id: "delete-all", icon:
|
|
29
|
+
{ id: "add", icon: Aa, label: "Add", tip: "Add a model file to the current plate (existing objects are kept)", run: t.add },
|
|
30
|
+
{ id: "delete", icon: nr, label: "Delete", tip: "Delete the selected object (Del)", run: t.remove },
|
|
31
|
+
{ id: "delete-all", icon: za, label: "Delete all", tip: "Delete every object on the plate", run: t.removeAll, disabled: () => t.objectCount() === 0 },
|
|
31
32
|
{ sep: !0 },
|
|
32
|
-
{ id: "duplicate", icon:
|
|
33
|
-
{ id: "split", icon:
|
|
34
|
-
{ id: "onbed", icon:
|
|
33
|
+
{ id: "duplicate", icon: Ra, label: "Duplicate", tip: "Duplicate the selected object (Ctrl+K)", run: t.duplicate },
|
|
34
|
+
{ id: "split", icon: rr, label: "Split", tip: "Split to objects — every disconnected part (connected component) becomes its own object. Split to parts is not implemented (no part concept)", run: t.split },
|
|
35
|
+
{ id: "onbed", icon: Da, label: "Place on bed", tip: "Drop every object onto the bed (Z=0) — to re-seat after lifting with the gizmo", run: t.placeOnBed },
|
|
35
36
|
{ sep: !0 },
|
|
36
|
-
{ id: "arrange", icon:
|
|
37
|
-
{ id: "orient", icon:
|
|
37
|
+
{ id: "arrange", icon: Ca, label: "Arrange", tip: "Auto arrange — lay objects out on the bed without overlap. Not implemented (needs the libslic3r Arrange port)" },
|
|
38
|
+
{ id: "orient", icon: Ia, label: "Orient", tip: "Auto orient — rotate to the orientation needing the least support. Not implemented (needs the libslic3r Orient port)" },
|
|
38
39
|
{ sep: !0 },
|
|
39
|
-
{ id: "cut", icon:
|
|
40
|
-
{ id: "boolean", icon:
|
|
41
|
-
{ id: "negative", icon:
|
|
40
|
+
{ id: "cut", icon: Pa, label: "Cut", tip: "Cut — slice the model with a plane into two pieces. Not implemented (needs cut-surface re-stitching)" },
|
|
41
|
+
{ id: "boolean", icon: ja, label: "Boolean", tip: "Mesh boolean — union/difference/intersection of two objects. Not implemented (needs the CGAL boolean port)" },
|
|
42
|
+
{ id: "negative", icon: Ba, label: "Negative part", tip: "Add a negative/modifier part — put a part with different properties inside one object. Not implemented (no part concept)" },
|
|
42
43
|
{ sep: !0 },
|
|
43
|
-
{ id: "seam", icon:
|
|
44
|
-
{ id: "mmu", icon:
|
|
45
|
-
{ id: "text", icon:
|
|
46
|
-
{ id: "measure", icon:
|
|
47
|
-
{ id: "varlayer", icon:
|
|
44
|
+
{ id: "seam", icon: Ua, label: "Seam painting", tip: "Seam painting — brush where the layer seam goes. Not implemented (needs kernel seam wiring)" },
|
|
45
|
+
{ id: "mmu", icon: Sa, label: "Color painting", tip: "Color painting — assign multi-material colors per facet. Not implemented (needs the MMU paint codec wiring)" },
|
|
46
|
+
{ id: "text", icon: Wa, label: "Text", tip: "Text/SVG emboss — engrave letters or shapes onto the model surface. Not implemented (needs font rasterization)" },
|
|
47
|
+
{ id: "measure", icon: La, label: "Measure", tip: "Measure — distance and angle between two points or faces. Not implemented" },
|
|
48
|
+
{ id: "varlayer", icon: Ha, label: "Variable layers", tip: "Variable layer height — different layer heights per band. Not implemented (the kernel has no variable z)" }
|
|
48
49
|
];
|
|
49
50
|
}
|
|
50
|
-
function
|
|
51
|
-
return (
|
|
52
|
-
var
|
|
53
|
-
const c =
|
|
51
|
+
function Xa(t) {
|
|
52
|
+
return (r) => {
|
|
53
|
+
var j;
|
|
54
|
+
const c = r.composedPath ? r.composedPath()[0] : r.target;
|
|
54
55
|
if (c && (c.tagName === "INPUT" || c.tagName === "TEXTAREA" || c.tagName === "SELECT" || c.isContentEditable)) return;
|
|
55
|
-
const
|
|
56
|
-
|
|
56
|
+
const i = r.key, o = typeof i == "string" ? i.toLowerCase() : "", p = r.ctrlKey || r.metaKey, h = () => {
|
|
57
|
+
r.preventDefault(), r.stopPropagation();
|
|
57
58
|
};
|
|
58
|
-
if (
|
|
59
|
-
|
|
59
|
+
if (p) {
|
|
60
|
+
o === "r" ? (h(), t.slicing || t.slice("current")) : o === "c" ? (h(), t.copy()) : o === "v" ? (h(), t.paste()) : o === "x" ? (h(), t.copy(), t.remove()) : (o === "k" || o === "d") && (h(), t.duplicate());
|
|
60
61
|
return;
|
|
61
62
|
}
|
|
62
|
-
if (
|
|
63
|
-
const
|
|
64
|
-
|
|
63
|
+
if (t.isPreview()) {
|
|
64
|
+
const x = r.shiftKey ? 10 : 1;
|
|
65
|
+
i === "ArrowUp" ? (h(), t.stepLayer(x)) : i === "ArrowDown" ? (h(), t.stepLayer(-x)) : o === "l" ? (h(), t.toggleSingleLayer()) : o === "t" ? (h(), t.toggleTravel()) : o === "z" ? (h(), t.zoomAll()) : o === "b" ? (h(), t.zoomBed()) : i === "Escape" && (h(), t.leavePreview());
|
|
65
66
|
return;
|
|
66
67
|
}
|
|
67
|
-
if (
|
|
68
|
-
|
|
69
|
-
else if (
|
|
70
|
-
|
|
71
|
-
else if (
|
|
72
|
-
|
|
73
|
-
else if (
|
|
74
|
-
|
|
75
|
-
else if (
|
|
76
|
-
|
|
77
|
-
else if (
|
|
78
|
-
|
|
79
|
-
else if (
|
|
80
|
-
|
|
81
|
-
else if (
|
|
82
|
-
|
|
83
|
-
else if (
|
|
84
|
-
|
|
85
|
-
else if ((
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
68
|
+
if (o === "m" || o === "g")
|
|
69
|
+
h(), t.setGizmo("translate");
|
|
70
|
+
else if (o === "r")
|
|
71
|
+
h(), t.setGizmo("rotate");
|
|
72
|
+
else if (o === "s")
|
|
73
|
+
h(), t.setGizmo("scale");
|
|
74
|
+
else if (o === "z")
|
|
75
|
+
h(), t.zoomAll();
|
|
76
|
+
else if (o === "b")
|
|
77
|
+
h(), t.zoomBed();
|
|
78
|
+
else if (i === "Delete" || i === "Backspace")
|
|
79
|
+
h(), t.remove();
|
|
80
|
+
else if (i === "Escape")
|
|
81
|
+
h(), t.cancelTool();
|
|
82
|
+
else if (i === "PageUp")
|
|
83
|
+
h(), t.rotateSelected(Math.PI / 4);
|
|
84
|
+
else if (i === "PageDown")
|
|
85
|
+
h(), t.rotateSelected(-Math.PI / 4);
|
|
86
|
+
else if ((j = i.startsWith) != null && j.call(i, "Arrow")) {
|
|
87
|
+
h();
|
|
88
|
+
const x = r.shiftKey ? 1 : 10;
|
|
89
|
+
t.nudgeSelected(
|
|
90
|
+
i === "ArrowLeft" ? -x : i === "ArrowRight" ? x : 0,
|
|
91
|
+
i === "ArrowUp" ? -x : i === "ArrowDown" ? x : 0
|
|
91
92
|
);
|
|
92
|
-
} else
|
|
93
|
+
} else i === "?" && (h(), t.toggleHelp());
|
|
93
94
|
};
|
|
94
95
|
}
|
|
95
|
-
function
|
|
96
|
-
const c =
|
|
97
|
-
if (!
|
|
98
|
-
const
|
|
99
|
-
for (let
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
if (!
|
|
104
|
-
const
|
|
105
|
-
return
|
|
96
|
+
function Ya(t, r) {
|
|
97
|
+
const c = t.geometry, i = c == null ? void 0 : c.getAttribute("position");
|
|
98
|
+
if (!i) return null;
|
|
99
|
+
const o = c.getIndex(), p = (o ? o.count : i.count) / 3, h = Math.cos(Math.max(0, Math.min(90, r)) * Math.PI / 180), j = new W.Matrix3().getNormalMatrix(t.matrixWorld), x = new W.Vector3(), B = new W.Vector3(), z = new W.Vector3(), m = new W.Vector3(), L = new W.Vector3(), D = new W.Vector3(), R = [];
|
|
100
|
+
for (let J = 0; J < p; J++) {
|
|
101
|
+
const _ = o ? o.getX(J * 3) : J * 3, T = o ? o.getX(J * 3 + 1) : J * 3 + 1, F = o ? o.getX(J * 3 + 2) : J * 3 + 2;
|
|
102
|
+
x.fromBufferAttribute(i, _), B.fromBufferAttribute(i, T), z.fromBufferAttribute(i, F), D.copy(m.subVectors(B, x)).cross(L.subVectors(z, x)), D.lengthSq() !== 0 && (D.applyMatrix3(j).normalize(), !(-D.y <= h) && R.push(x.x, x.y, x.z, B.x, B.y, B.z, z.x, z.y, z.z));
|
|
103
|
+
}
|
|
104
|
+
if (!R.length) return null;
|
|
105
|
+
const K = new W.BufferGeometry();
|
|
106
|
+
return K.setAttribute("position", new W.Float32BufferAttribute(R, 3)), K.computeVertexNormals(), K;
|
|
106
107
|
}
|
|
107
|
-
function
|
|
108
|
-
const
|
|
109
|
-
for (let
|
|
110
|
-
c[
|
|
111
|
-
let
|
|
112
|
-
for (let
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
for (let
|
|
116
|
-
c[
|
|
117
|
-
return { localPos: c, size: { w:
|
|
108
|
+
function Ka(t) {
|
|
109
|
+
const r = t.length, c = new Float32Array(r);
|
|
110
|
+
for (let m = 0; m < r; m += 3)
|
|
111
|
+
c[m] = t[m], c[m + 1] = t[m + 2], c[m + 2] = -t[m + 1];
|
|
112
|
+
let i = 1 / 0, o = 1 / 0, p = 1 / 0, h = -1 / 0, j = -1 / 0, x = -1 / 0;
|
|
113
|
+
for (let m = 0; m < r; m += 3)
|
|
114
|
+
i = Math.min(i, c[m]), h = Math.max(h, c[m]), o = Math.min(o, c[m + 1]), j = Math.max(j, c[m + 1]), p = Math.min(p, c[m + 2]), x = Math.max(x, c[m + 2]);
|
|
115
|
+
const B = (i + h) / 2, z = (p + x) / 2;
|
|
116
|
+
for (let m = 0; m < r; m += 3)
|
|
117
|
+
c[m] -= B, c[m + 1] -= o, c[m + 2] -= z;
|
|
118
|
+
return { localPos: c, size: { w: h - i, d: x - p, h: j - o } };
|
|
118
119
|
}
|
|
119
|
-
function
|
|
120
|
+
function Ja(t) {
|
|
120
121
|
const {
|
|
121
|
-
apiRef:
|
|
122
|
+
apiRef: r,
|
|
122
123
|
objectsRef: c,
|
|
123
|
-
keyRef:
|
|
124
|
-
workerRef:
|
|
125
|
-
selectedPlateRef:
|
|
126
|
-
placeXRef:
|
|
127
|
-
plateCountRef:
|
|
128
|
-
canvasModeRef:
|
|
129
|
-
paintModeRef:
|
|
130
|
-
brushRadiusRef:
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
124
|
+
keyRef: i,
|
|
125
|
+
workerRef: o,
|
|
126
|
+
selectedPlateRef: p,
|
|
127
|
+
placeXRef: h,
|
|
128
|
+
plateCountRef: j,
|
|
129
|
+
canvasModeRef: x,
|
|
130
|
+
paintModeRef: B,
|
|
131
|
+
brushRadiusRef: z,
|
|
132
|
+
paintToolRef: m,
|
|
133
|
+
paintXformRef: L,
|
|
134
|
+
extruderColorsRef: D,
|
|
135
|
+
setOk: R,
|
|
136
|
+
setStatus: K,
|
|
137
|
+
setGmode: J,
|
|
138
|
+
setCtxMenu: _,
|
|
139
|
+
setBrushRadius: T
|
|
140
|
+
} = t, F = ne(null), ce = ne({}), pe = ne(!1), w = ne(200), S = ne(200);
|
|
141
|
+
function E(y) {
|
|
142
|
+
const v = Ft(j.current);
|
|
143
|
+
return { x: y % v * rt(w.current), z: Math.floor(y / v) * rt(S.current) };
|
|
144
|
+
}
|
|
145
|
+
function M(y, v) {
|
|
146
|
+
const C = j.current, V = Ft(C), f = Math.max(0, Math.min(V - 1, Math.round(y / rt(w.current)))), N = Math.max(0, Math.round(v / rt(S.current)));
|
|
147
|
+
return Math.max(0, Math.min(C - 1, N * V + f));
|
|
148
|
+
}
|
|
149
|
+
return Te(() => {
|
|
150
|
+
const y = F.current;
|
|
151
|
+
if (!y) return;
|
|
152
|
+
const v = document.createElement("canvas");
|
|
153
|
+
if (!(v.getContext("webgl2") || v.getContext("webgl"))) {
|
|
154
|
+
R(!1), K("Cannot create a WebGL context in this environment (headless / no GPU).");
|
|
153
155
|
return;
|
|
154
156
|
}
|
|
155
|
-
let
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
if (!
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
Number.isFinite(
|
|
157
|
+
let C = y.clientWidth || 800, V = y.clientHeight || 480;
|
|
158
|
+
const f = new W.WebGLRenderer({ antialias: !0 });
|
|
159
|
+
f.setPixelRatio(Math.min(window.devicePixelRatio, 2)), f.setSize(C, V), f.setClearColor(1448478, 1), f.domElement.setAttribute("data-webgl", f.getContext() ? "ok" : "fail"), y.appendChild(f.domElement);
|
|
160
|
+
const N = new W.Scene(), O = new W.PerspectiveCamera(50, C / V, 1, 3e3);
|
|
161
|
+
O.position.set(210, 180, 260), N.add(new W.HemisphereLight(16777215, 2764598, 1));
|
|
162
|
+
const H = new W.DirectionalLight(16777215, 1.1);
|
|
163
|
+
H.position.set(120, 220, 160), N.add(H);
|
|
164
|
+
const oe = new W.Group();
|
|
165
|
+
N.add(oe);
|
|
166
|
+
const ue = new W.Group();
|
|
167
|
+
N.add(ue);
|
|
168
|
+
const $ = new ga(O, f.domElement);
|
|
169
|
+
$.target.set(0, 22, 0), $.enableDamping = !1, $.update(), $.rotateSpeed = 1.6, $.panSpeed = 1.6;
|
|
170
|
+
const P = new ya(O, f.domElement);
|
|
171
|
+
P.setMode("translate"), P.setSize(0.8);
|
|
172
|
+
const ve = new W.Box3(), Me = (a) => {
|
|
173
|
+
if (!a) return;
|
|
174
|
+
a.updateMatrixWorld(!0), ve.setFromObject(a);
|
|
175
|
+
const l = ve.min.y;
|
|
176
|
+
Number.isFinite(l) && Math.abs(l) > 1e-4 && (a.position.y -= l, a.updateMatrixWorld(!0));
|
|
177
|
+
}, ge = new W.Matrix4(), Ee = new W.Matrix4(), b = /* @__PURE__ */ new Map();
|
|
178
|
+
let k = !1;
|
|
179
|
+
P.addEventListener("objectChange", () => {
|
|
180
|
+
if (!(!k || !P.object)) {
|
|
181
|
+
P.object.updateMatrixWorld(!0), Ee.copy(P.object.matrixWorld).multiply(ge);
|
|
182
|
+
for (const [a, l] of b)
|
|
183
|
+
a.matrixAutoUpdate = !1, a.matrix.multiplyMatrices(Ee, l);
|
|
184
|
+
}
|
|
185
|
+
}), P.addEventListener("dragging-changed", (a) => {
|
|
186
|
+
var l, U, Y, re, X, ke, ze;
|
|
187
|
+
if ($.enabled = !a.value, a.value) {
|
|
188
|
+
b.clear();
|
|
189
|
+
const Ce = (l = t.paintOverlayRef) == null ? void 0 : l.current;
|
|
190
|
+
if (k = !!(Ce && Ce.size && P.object && !((U = P.object.userData) != null && U.isPrimeTower)), k) {
|
|
191
|
+
P.object.updateMatrixWorld(!0), ge.copy(P.object.matrixWorld).invert();
|
|
192
|
+
for (const be of Ce.values()) b.set(be, be.matrix.clone());
|
|
193
|
+
}
|
|
194
|
+
} else k = !1;
|
|
195
|
+
if (!a.value)
|
|
196
|
+
if (P.object && ((Y = P.object.userData) != null && Y.isPrimeTower)) {
|
|
197
|
+
P.object.position.y = P.object.userData.halfHeight;
|
|
198
|
+
const Ce = P.object.scale.x / 2;
|
|
199
|
+
(re = t.onTowerMoved) == null || re.call(t, P.object.position.x - Ce, -P.object.position.z - Ce);
|
|
200
|
+
} else
|
|
201
|
+
Me(P.object), (X = t.onTransformCommitted) == null || X.call(t);
|
|
202
|
+
(ze = (ke = ce.current).invalidate) == null || ze.call(ke);
|
|
203
|
+
}), N.add(P), ce.current = { scene: N, camera: O, renderer: f, orbit: $, transform: P, objectsGroup: oe, toolpathGroup: ue, plateBeds: [] }, typeof window < "u" && (window.__vpThree = ce.current, window.__vpApi = () => r.current);
|
|
204
|
+
let G = !0;
|
|
205
|
+
const q = () => {
|
|
206
|
+
G = !0;
|
|
175
207
|
};
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}), D.add(C), _.current = { scene: D, camera: W, renderer: v, orbit: Y, transform: C, objectsGroup: ge, toolpathGroup: de, plateBeds: [] }, typeof window < "u" && (window.__vpThree = _.current, window.__vpApi = () => a.current);
|
|
180
|
-
let Ce = !0;
|
|
208
|
+
ce.current.invalidate = q, $.addEventListener("change", q), P.addEventListener("change", q), f.domElement.addEventListener("pointermove", q);
|
|
209
|
+
const s = new W.Raycaster(), d = new W.Vector2();
|
|
210
|
+
let A = null, u = null, I = 0, se = null;
|
|
181
211
|
const ye = () => {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
(me = r.current) == null || me.postMessage({
|
|
212
|
+
const a = c.current.map((l) => l.mesh);
|
|
213
|
+
return se && se.visible && a.push(se), a;
|
|
214
|
+
}, xe = () => {
|
|
215
|
+
var a;
|
|
216
|
+
for (const l of ye())
|
|
217
|
+
l.material.emissive ? l.material.emissive.setHex(l === u ? 44610 : l === A ? 2055220 : 0) : (a = l.userData) != null && a.isPrimeTower && (l.material.opacity = l === u ? 0.6 : l === A ? 0.5 : 0.35);
|
|
218
|
+
}, je = () => c.current.length ? `${c.current.length} object(s) · selected: ${u ? u.userData.name : "—"} | M/R/S · left-drag to orbit · ? for shortcuts` : `hover: ${A ? A.userData.name : "—"} · selected: ${u ? u.userData.name : "—"} | left-drag to orbit · ? for shortcuts`, Q = (a) => {
|
|
219
|
+
const l = f.domElement.getBoundingClientRect();
|
|
220
|
+
d.x = (a.clientX - l.left) / l.width * 2 - 1, d.y = -((a.clientY - l.top) / l.height) * 2 + 1;
|
|
221
|
+
}, Z = () => {
|
|
222
|
+
s.setFromCamera(d, O);
|
|
223
|
+
const a = s.intersectObjects(ye(), !1);
|
|
224
|
+
return a.length ? a[0].object : null;
|
|
225
|
+
}, ee = () => {
|
|
226
|
+
s.setFromCamera(d, O);
|
|
227
|
+
const a = s.intersectObjects(ye(), !1);
|
|
228
|
+
return a.length ? a[0] : null;
|
|
229
|
+
}, he = (a) => {
|
|
230
|
+
var ze;
|
|
231
|
+
const l = L.current;
|
|
232
|
+
if (!l) return;
|
|
233
|
+
Q(a);
|
|
234
|
+
const U = ee();
|
|
235
|
+
if (!U || U.faceIndex == null) return;
|
|
236
|
+
const Y = (Ce) => [Ce.x - l.cx, -Ce.z - l.cy, Ce.y - l.minz], re = Y(U.point), X = Y(O.position), ke = (m == null ? void 0 : m.current) ?? { tool: "brush", cursor: "sphere", angle: 30 };
|
|
237
|
+
(ze = o.current) == null || ze.postMessage({
|
|
209
238
|
cmd: "paint",
|
|
210
|
-
facet:
|
|
239
|
+
facet: U.faceIndex,
|
|
211
240
|
hx: re[0],
|
|
212
241
|
hy: re[1],
|
|
213
242
|
hz: re[2],
|
|
214
|
-
cx:
|
|
215
|
-
cy:
|
|
216
|
-
cz:
|
|
217
|
-
radius:
|
|
218
|
-
enforcer:
|
|
243
|
+
cx: X[0],
|
|
244
|
+
cy: X[1],
|
|
245
|
+
cz: X[2],
|
|
246
|
+
radius: z.current,
|
|
247
|
+
enforcer: B.current === "enforcer",
|
|
248
|
+
tool: ke.tool,
|
|
249
|
+
cursor: ke.cursor,
|
|
250
|
+
angle: ke.angle
|
|
219
251
|
});
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
252
|
+
};
|
|
253
|
+
let me = null, fe = 0;
|
|
254
|
+
const le = () => {
|
|
255
|
+
fe = 0;
|
|
256
|
+
const a = me;
|
|
257
|
+
me = null, a && he(a);
|
|
258
|
+
}, Ae = (a) => {
|
|
259
|
+
me = a, fe || (fe = requestAnimationFrame(le));
|
|
260
|
+
}, Pe = () => {
|
|
261
|
+
var l;
|
|
262
|
+
const a = (l = m == null ? void 0 : m.current) == null ? void 0 : l.tool;
|
|
263
|
+
return a === "smart" || a === "bucket" || a === "triangle";
|
|
264
|
+
}, Re = () => {
|
|
265
|
+
const a = f.domElement;
|
|
266
|
+
a.style.cursor = x.current === "preview" ? "" : B.current !== "off" ? "crosshair" : A ? "pointer" : "";
|
|
267
|
+
}, qe = (a) => {
|
|
268
|
+
if (x.current === "preview") return;
|
|
269
|
+
if (B.current !== "off") {
|
|
270
|
+
pe.current && !Pe() && Ae(a);
|
|
227
271
|
return;
|
|
228
272
|
}
|
|
229
|
-
if (
|
|
230
|
-
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
},
|
|
234
|
-
if (
|
|
235
|
-
if (
|
|
236
|
-
|
|
273
|
+
if (P.dragging || P.axis) return;
|
|
274
|
+
Q(a);
|
|
275
|
+
const l = Z();
|
|
276
|
+
l !== A && (A = l, xe(), Re(), K(je()));
|
|
277
|
+
}, dt = (a) => {
|
|
278
|
+
if (a.button !== 0 || x.current === "preview") return;
|
|
279
|
+
if (B.current !== "off") {
|
|
280
|
+
pe.current = !0, $.enabled = !1, he(a);
|
|
237
281
|
return;
|
|
238
282
|
}
|
|
239
|
-
if (
|
|
240
|
-
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
},
|
|
244
|
-
|
|
245
|
-
},
|
|
246
|
-
|
|
247
|
-
},
|
|
248
|
-
if (
|
|
249
|
-
|
|
250
|
-
const
|
|
251
|
-
|
|
283
|
+
if (P.dragging || P.axis) return;
|
|
284
|
+
Q(a);
|
|
285
|
+
const l = Z();
|
|
286
|
+
l ? (u = l, P.attach(l)) : (u = null, P.detach()), xe(), K(je());
|
|
287
|
+
}, Xe = () => {
|
|
288
|
+
pe.current && (pe.current = !1, $.enabled = !0, fe && (cancelAnimationFrame(fe), le()));
|
|
289
|
+
}, Je = (a) => {
|
|
290
|
+
a.button !== 0 || x.current === "preview" || B.current !== "off" || (Q(a), Z() ? mt() : (u = null, P.detach(), xe(), K(je())));
|
|
291
|
+
}, Nt = (a) => {
|
|
292
|
+
if (B.current === "off" || x.current === "preview" || Pe()) return;
|
|
293
|
+
a.preventDefault(), a.stopPropagation();
|
|
294
|
+
const l = Math.min(15, Math.max(1, z.current + (a.deltaY < 0 ? 0.5 : -0.5)));
|
|
295
|
+
z.current = l, T(l);
|
|
252
296
|
};
|
|
253
|
-
let
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
},
|
|
257
|
-
if (
|
|
258
|
-
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
const
|
|
262
|
-
|
|
297
|
+
let $e = null;
|
|
298
|
+
const Mt = (a) => {
|
|
299
|
+
a.button === 2 && ($e = { x: a.clientX, y: a.clientY });
|
|
300
|
+
}, At = (a) => {
|
|
301
|
+
if (a.preventDefault(), x.current === "preview" || B.current !== "off" || $e && Math.hypot(a.clientX - $e.x, a.clientY - $e.y) > 4) return;
|
|
302
|
+
Q(a);
|
|
303
|
+
const l = Z();
|
|
304
|
+
l ? (u = l, P.attach(l)) : (u = null, P.detach()), xe(), K(je());
|
|
305
|
+
const U = f.domElement.getBoundingClientRect();
|
|
306
|
+
_({ x: a.clientX - U.left, y: a.clientY - U.top, onObject: !!l });
|
|
263
307
|
};
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
},
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
},
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
const
|
|
276
|
-
if (
|
|
277
|
-
|
|
308
|
+
f.domElement.addEventListener("pointermove", qe), f.domElement.addEventListener("pointerdown", dt), f.domElement.addEventListener("pointerdown", Mt), f.domElement.addEventListener("contextmenu", At), f.domElement.addEventListener("dblclick", Je), f.domElement.addEventListener("wheel", Nt, { passive: !1, capture: !0 }), window.addEventListener("pointerup", Xe), window.addEventListener("pointercancel", Xe);
|
|
309
|
+
const Ct = (a) => {
|
|
310
|
+
P.setMode(a), J(a);
|
|
311
|
+
}, mt = () => {
|
|
312
|
+
const a = c.current, l = new W.Box3();
|
|
313
|
+
a.length ? a.forEach((X) => l.expandByObject(X.mesh)) : l.setFromCenterAndSize(new W.Vector3(0, 25, 0), new W.Vector3(100, 50, 100));
|
|
314
|
+
const U = l.getCenter(new W.Vector3()), Y = l.getSize(new W.Vector3()), re = Math.max(Y.x, Y.y, Y.z, 20) * 1.9 + 40;
|
|
315
|
+
$.target.copy(U), O.position.set(U.x + re * 0.7, U.y + re * 0.55 + Y.y * 0.3, U.z + re), O.updateProjectionMatrix(), $.update();
|
|
316
|
+
}, ft = (a, l, U = null, Y = null, re = null) => {
|
|
317
|
+
const X = new W.BufferGeometry();
|
|
318
|
+
X.setAttribute("position", new W.Float32BufferAttribute(l, 3)), X.computeVertexNormals(), X.computeBoundingBox();
|
|
319
|
+
const ke = D.current[0] || "#6aa0dc", ze = new W.Mesh(X, new W.MeshStandardMaterial({ color: new W.Color(ke), roughness: 0.6, metalness: 0.05, side: W.DoubleSide }));
|
|
320
|
+
if (U && ze.rotation.copy(U), Y && ze.scale.copy(Y), re)
|
|
321
|
+
ze.position.copy(re);
|
|
278
322
|
else {
|
|
279
|
-
const
|
|
280
|
-
c.current.length === 0 && (
|
|
281
|
-
const
|
|
282
|
-
|
|
323
|
+
const be = (X.boundingBox.max.x - X.boundingBox.min.x) * (Y ? Math.abs(Y.x) : 1);
|
|
324
|
+
c.current.length === 0 && (h.current = 0);
|
|
325
|
+
const Se = E(p.current);
|
|
326
|
+
ze.position.set(Se.x + h.current + be / 2, 0, Se.z), h.current += be + 8;
|
|
283
327
|
}
|
|
284
|
-
|
|
285
|
-
const
|
|
286
|
-
return c.current.push({ id:
|
|
328
|
+
ze.userData = { name: a }, oe.add(ze);
|
|
329
|
+
const Ce = ++I;
|
|
330
|
+
return c.current.push({ id: Ce, name: a, mesh: ze, localPos: l, extruder: 1, visible: !0 }), oe.visible = !0, at != null && ht(), K(je()), mt(), { id: Ce, name: a };
|
|
287
331
|
};
|
|
288
|
-
let
|
|
289
|
-
function
|
|
290
|
-
for (const
|
|
291
|
-
const
|
|
292
|
-
var
|
|
293
|
-
return (
|
|
332
|
+
let at = null;
|
|
333
|
+
function ht() {
|
|
334
|
+
for (const a of c.current) {
|
|
335
|
+
const l = a.mesh.children.find((re) => {
|
|
336
|
+
var X;
|
|
337
|
+
return (X = re.userData) == null ? void 0 : X.overhang;
|
|
294
338
|
});
|
|
295
|
-
if (
|
|
296
|
-
|
|
297
|
-
const
|
|
298
|
-
if (!
|
|
299
|
-
const
|
|
339
|
+
if (l && (a.mesh.remove(l), l.geometry.dispose(), l.material.dispose()), at == null) continue;
|
|
340
|
+
a.mesh.updateWorldMatrix(!0, !1);
|
|
341
|
+
const U = Ya(a.mesh, at);
|
|
342
|
+
if (!U) continue;
|
|
343
|
+
const Y = new W.Mesh(U, new W.MeshBasicMaterial({
|
|
300
344
|
color: 16729139,
|
|
301
345
|
transparent: !0,
|
|
302
346
|
opacity: 0.7,
|
|
303
|
-
side:
|
|
347
|
+
side: W.DoubleSide,
|
|
304
348
|
depthWrite: !1,
|
|
305
349
|
polygonOffset: !0,
|
|
306
350
|
polygonOffsetFactor: -1,
|
|
307
351
|
polygonOffsetUnits: -1
|
|
308
352
|
}));
|
|
309
|
-
|
|
353
|
+
Y.userData.overhang = !0, a.mesh.add(Y);
|
|
310
354
|
}
|
|
311
|
-
|
|
355
|
+
q();
|
|
312
356
|
}
|
|
313
|
-
|
|
314
|
-
!
|
|
315
|
-
}),
|
|
316
|
-
setMode:
|
|
357
|
+
P.addEventListener("dragging-changed", (a) => {
|
|
358
|
+
!a.value && at != null && ht();
|
|
359
|
+
}), r.current = {
|
|
360
|
+
setMode: Ct,
|
|
317
361
|
/** Highlight facets below `thresholdDeg` (the support threshold angle); null turns the shading off. */
|
|
318
|
-
setOverhang: (
|
|
319
|
-
|
|
362
|
+
setOverhang: (a) => {
|
|
363
|
+
at = a, ht();
|
|
320
364
|
},
|
|
321
|
-
refreshCursor: () =>
|
|
365
|
+
refreshCursor: () => Re(),
|
|
322
366
|
// keeps the cursor hint in sync when the paint mode changes
|
|
323
367
|
detachTransform: () => {
|
|
324
|
-
|
|
368
|
+
u = null, P.detach(), xe();
|
|
325
369
|
},
|
|
326
370
|
// stage 20: release the gizmo when entering painting
|
|
327
|
-
addObject: (
|
|
371
|
+
addObject: (a, l) => ft(a, Ka(l).localPos),
|
|
328
372
|
// ---- Shortcut support (duplicate/nudge/rotate/zoom-to) ----
|
|
329
|
-
getSnapshot: (
|
|
330
|
-
const
|
|
331
|
-
return
|
|
373
|
+
getSnapshot: (a) => {
|
|
374
|
+
const l = c.current.find((U) => U.id === a);
|
|
375
|
+
return l ? { name: l.name, localPos: l.localPos, rot: l.mesh.rotation.clone(), scale: l.mesh.scale.clone(), pos: l.mesh.position.clone() } : null;
|
|
332
376
|
},
|
|
333
377
|
// keepPos=true keeps the snapshot's original position (split). false (default) places it beside via the placement cursor (duplicate/paste).
|
|
334
|
-
spawnSnapshot: (
|
|
335
|
-
nudgeSelected: (
|
|
336
|
-
|
|
378
|
+
spawnSnapshot: (a, l = !1) => a ? ft(a.name, a.localPos, a.rot, a.scale, l && a.pos || null) : null,
|
|
379
|
+
nudgeSelected: (a, l) => {
|
|
380
|
+
u && (u.position.x += a, u.position.z += l);
|
|
337
381
|
},
|
|
338
|
-
rotateSelectedY: (
|
|
339
|
-
|
|
382
|
+
rotateSelectedY: (a) => {
|
|
383
|
+
u && (u.rotation.y += a);
|
|
340
384
|
},
|
|
341
|
-
frame: () =>
|
|
385
|
+
frame: () => mt(),
|
|
342
386
|
// Z: zoom to all objects
|
|
343
387
|
frameBed: () => {
|
|
344
|
-
const
|
|
345
|
-
|
|
388
|
+
const a = E(p.current), l = Math.max(w.current, S.current) * 1.1 + 40;
|
|
389
|
+
$.target.set(a.x, 0, a.z), O.position.set(a.x + l * 0.55, l * 0.8, a.z + l), $.update();
|
|
346
390
|
},
|
|
347
|
-
removeObject: (
|
|
348
|
-
var re,
|
|
349
|
-
const
|
|
350
|
-
if (
|
|
351
|
-
const
|
|
352
|
-
|
|
353
|
-
for (const
|
|
354
|
-
|
|
355
|
-
|
|
391
|
+
removeObject: (a) => {
|
|
392
|
+
var re, X;
|
|
393
|
+
const l = c.current, U = l.findIndex((ke) => ke.id === a);
|
|
394
|
+
if (U < 0) return;
|
|
395
|
+
const Y = l[U];
|
|
396
|
+
u === Y.mesh && (u = null, P.detach()), A === Y.mesh && (A = null);
|
|
397
|
+
for (const ke of [...Y.mesh.children])
|
|
398
|
+
Y.mesh.remove(ke), (re = ke.geometry) == null || re.dispose(), (X = ke.material) == null || X.dispose();
|
|
399
|
+
oe.remove(Y.mesh), Y.mesh.geometry.dispose(), Y.mesh.material.dispose(), l.splice(U, 1), l.length === 0 && (h.current = 0), xe(), K(je());
|
|
356
400
|
},
|
|
357
401
|
// MM: merges triangles sorted by ascending extruder -> group0 (ext1) followed by group1 (ext2); returns split.
|
|
358
|
-
platePos: (
|
|
402
|
+
platePos: (a) => E(a),
|
|
359
403
|
// three (x,z) offset of plate i
|
|
360
|
-
plateOfObject: (
|
|
361
|
-
|
|
362
|
-
const
|
|
363
|
-
return
|
|
404
|
+
plateOfObject: (a) => {
|
|
405
|
+
a.mesh.updateMatrixWorld(!0);
|
|
406
|
+
const l = new W.Vector3().setFromMatrixPosition(a.mesh.matrixWorld);
|
|
407
|
+
return M(l.x, l.z);
|
|
364
408
|
},
|
|
365
409
|
// When plateIdx != null, only objects on that plate are used and coordinates are converted to plate-local (three-x -= PX) (keeps the stage-28 contract).
|
|
366
|
-
buildMergedSTL: (
|
|
367
|
-
let
|
|
368
|
-
if (
|
|
369
|
-
|
|
370
|
-
const
|
|
371
|
-
return
|
|
372
|
-
})), !
|
|
373
|
-
const
|
|
374
|
-
let
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
410
|
+
buildMergedSTL: (a = null) => {
|
|
411
|
+
let l = c.current.filter((de) => de.visible !== !1);
|
|
412
|
+
if (a != null && (l = l.filter((de) => {
|
|
413
|
+
de.mesh.updateMatrixWorld(!0);
|
|
414
|
+
const Fe = new W.Vector3().setFromMatrixPosition(de.mesh.matrixWorld);
|
|
415
|
+
return M(Fe.x, Fe.z) === a;
|
|
416
|
+
})), !l.length) return null;
|
|
417
|
+
const U = [...l].sort((de, Fe) => (de.extruder || 1) - (Fe.extruder || 1)), Y = new Set(U.map((de) => de.extruder || 1)), re = new W.Vector3(), X = [];
|
|
418
|
+
let ke = 0, ze = 0;
|
|
419
|
+
const Ce = [], be = [], Se = [];
|
|
420
|
+
for (const de of U) {
|
|
421
|
+
const Fe = de.extruder || 1;
|
|
422
|
+
Se.push(`${de.id}:${Fe}:${de.localPos.length / 9}`), be.length === 0 ? be.push(Fe - 1) : Fe - 1 !== be[be.length - 1] && (Ce.push(ke), be.push(Fe - 1)), Fe >= 2 && ze === 0 && (ze = ke), de.mesh.updateMatrixWorld(!0);
|
|
423
|
+
const Zt = de.mesh.matrixWorld, st = de.localPos;
|
|
424
|
+
for (let tt = 0; tt < st.length; tt += 3)
|
|
425
|
+
re.set(st[tt], st[tt + 1], st[tt + 2]).applyMatrix4(Zt), X.push(re.x, -re.z, re.y);
|
|
426
|
+
ke += st.length / 9;
|
|
381
427
|
}
|
|
382
|
-
|
|
383
|
-
for (let
|
|
384
|
-
|
|
385
|
-
const
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
for (let xe = 0; xe < 3; xe++)
|
|
394
|
-
Le.setFloat32(_e, U[Te++], !0), Le.setFloat32(_e + 4, U[Te++], !0), Le.setFloat32(_e + 8, U[Te++], !0), _e += 12;
|
|
395
|
-
Le.setUint16(_e, 0, !0), _e += 2;
|
|
428
|
+
const Ve = E(a ?? p.current), ot = Ve.x, Ue = -Ve.z;
|
|
429
|
+
for (let de = 0; de < X.length; de += 3)
|
|
430
|
+
X[de] -= ot, X[de + 1] -= Ue;
|
|
431
|
+
const lt = Ve.x, we = Ve.z, _e = new ArrayBuffer(84 + ke * 50), Le = new DataView(_e);
|
|
432
|
+
Le.setUint32(80, ke, !0);
|
|
433
|
+
let Ie = 84, We = 0;
|
|
434
|
+
for (let de = 0; de < ke; de++) {
|
|
435
|
+
Ie += 12;
|
|
436
|
+
for (let Fe = 0; Fe < 3; Fe++)
|
|
437
|
+
Le.setFloat32(Ie, X[We++], !0), Le.setFloat32(Ie + 4, X[We++], !0), Le.setFloat32(Ie + 8, X[We++], !0), Ie += 12;
|
|
438
|
+
Le.setUint16(Ie, 0, !0), Ie += 2;
|
|
396
439
|
}
|
|
397
|
-
|
|
440
|
+
let Qe = 1e18, Ye = 1e18, et = -1e18, vt = -1e18;
|
|
441
|
+
for (let de = 0; de < X.length; de += 3)
|
|
442
|
+
X[de] < Qe && (Qe = X[de]), X[de] > et && (et = X[de]), X[de + 1] < Ye && (Ye = X[de + 1]), X[de + 1] > vt && (vt = X[de + 1]);
|
|
443
|
+
return {
|
|
444
|
+
buf: _e,
|
|
445
|
+
split: ze,
|
|
446
|
+
splits: Ce,
|
|
447
|
+
tools: be,
|
|
448
|
+
extruders: Y.size,
|
|
449
|
+
offX: lt,
|
|
450
|
+
offZ: we,
|
|
451
|
+
topology: Se.join("|"),
|
|
452
|
+
minX: Qe,
|
|
453
|
+
minY: Ye,
|
|
454
|
+
maxX: et,
|
|
455
|
+
maxY: vt
|
|
456
|
+
};
|
|
398
457
|
},
|
|
399
|
-
setObjectExtruder: (
|
|
400
|
-
const
|
|
401
|
-
if (
|
|
402
|
-
|
|
403
|
-
const
|
|
404
|
-
|
|
458
|
+
setObjectExtruder: (a, l) => {
|
|
459
|
+
const U = c.current.find((Y) => Y.id === a);
|
|
460
|
+
if (U) {
|
|
461
|
+
U.extruder = l;
|
|
462
|
+
const Y = D.current[l - 1];
|
|
463
|
+
Y && U.mesh.material.color.set(Y);
|
|
405
464
|
}
|
|
406
465
|
},
|
|
407
|
-
setObjectVisible: (
|
|
408
|
-
const
|
|
409
|
-
|
|
466
|
+
setObjectVisible: (a, l) => {
|
|
467
|
+
const U = c.current.find((Y) => Y.id === a);
|
|
468
|
+
U && (U.visible = l, U.mesh.visible = l);
|
|
410
469
|
},
|
|
411
470
|
// stage 27: print toggle (eye icon)
|
|
412
471
|
recolorObjects: () => {
|
|
413
|
-
for (const
|
|
414
|
-
const
|
|
415
|
-
|
|
472
|
+
for (const a of c.current) {
|
|
473
|
+
const l = D.current[(a.extruder || 1) - 1];
|
|
474
|
+
l && a.mesh.material.color.set(l);
|
|
416
475
|
}
|
|
417
476
|
},
|
|
418
477
|
// reflect filament color changes
|
|
419
478
|
selectedObjectId: () => {
|
|
420
|
-
var
|
|
421
|
-
return
|
|
479
|
+
var a;
|
|
480
|
+
return u ? ((a = c.current.find((l) => l.mesh === u)) == null ? void 0 : a.id) ?? null : null;
|
|
422
481
|
},
|
|
423
482
|
// stage 27: viewport toolbar "delete selected"
|
|
424
|
-
selectObject: (
|
|
425
|
-
const
|
|
426
|
-
|
|
483
|
+
selectObject: (a) => {
|
|
484
|
+
const l = c.current.find((U) => U.id === a);
|
|
485
|
+
l && (u = l.mesh, P.attach(l.mesh), xe(), K(je()));
|
|
427
486
|
},
|
|
428
487
|
// Stage 28 P1: seat on the bed — local geometry is baked to minZ->0 by bakeLocal (once on load). Re-seat after a gizmo Z move.
|
|
429
488
|
// (The upstream ensure_on_bed sinking allowance [allow_negative_z] is out of scope — we only seat by -min_z.)
|
|
430
489
|
placeOnBed: () => {
|
|
431
|
-
var
|
|
432
|
-
for (const
|
|
433
|
-
|
|
490
|
+
var a;
|
|
491
|
+
for (const l of c.current) l.mesh.position.y = 0;
|
|
492
|
+
u && ((a = P.update) == null || a.call(P));
|
|
434
493
|
},
|
|
435
494
|
onSliced: () => {
|
|
436
|
-
|
|
495
|
+
oe.visible = !1, P.detach(), u = null, xe();
|
|
437
496
|
},
|
|
438
497
|
showObjects: () => {
|
|
439
|
-
|
|
498
|
+
oe.visible = !0;
|
|
499
|
+
},
|
|
500
|
+
// Footprint + height of everything currently on the plate, in the same coordinates the tower box uses.
|
|
501
|
+
modelBounds: (a = null) => {
|
|
502
|
+
let l = c.current.filter((re) => re.visible !== !1);
|
|
503
|
+
a != null && (l = l.filter((re) => {
|
|
504
|
+
re.mesh.updateMatrixWorld(!0);
|
|
505
|
+
const X = new W.Vector3().setFromMatrixPosition(re.mesh.matrixWorld);
|
|
506
|
+
return M(X.x, X.z) === a;
|
|
507
|
+
}));
|
|
508
|
+
const U = l.map((re) => re.mesh);
|
|
509
|
+
if (!U.length) return null;
|
|
510
|
+
const Y = new W.Box3();
|
|
511
|
+
for (const re of U)
|
|
512
|
+
re.updateMatrixWorld(!0), Y.expandByObject(re);
|
|
513
|
+
return Number.isFinite(Y.min.x) ? { minX: Y.min.x, maxX: Y.max.x, minY: -Y.max.z, maxY: -Y.min.z, height: Y.max.y - Y.min.y } : null;
|
|
514
|
+
},
|
|
515
|
+
// Draw (or move) the tower stand-in. size/height in mm, x/y in the same bed-centred coordinates the objects
|
|
516
|
+
// use. Passing null removes it — a single-filament print has no tower to show.
|
|
517
|
+
setPrimeTower: (a) => {
|
|
518
|
+
var ke;
|
|
519
|
+
const l = ce.current;
|
|
520
|
+
if (!a) {
|
|
521
|
+
se && (u === se && (u = null, P.detach()), l.scene.remove(se), se.geometry.dispose(), se.material.dispose(), se = null);
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
const { x: U, y: Y, size: re, height: X } = a;
|
|
525
|
+
if (!se) {
|
|
526
|
+
const ze = new W.BoxGeometry(1, 1, 1), Ce = new W.MeshBasicMaterial({ color: 5231045, transparent: !0, opacity: 0.35, depthWrite: !1 });
|
|
527
|
+
se = new W.Mesh(ze, Ce), se.userData = { name: "Prime tower", isPrimeTower: !0 }, l.scene.add(se);
|
|
528
|
+
}
|
|
529
|
+
se.userData.halfHeight = X / 2, se.scale.set(re, X, re), se.position.set(U, X / 2, -Y), se.visible = !0, (ke = l.invalidate) == null || ke.call(l);
|
|
440
530
|
},
|
|
441
531
|
// Stage 29-2: render N plates — each plate = grid + border, offset by PX_i, with the selected plate's border highlighted.
|
|
442
|
-
setPlates: (
|
|
443
|
-
const re =
|
|
444
|
-
|
|
445
|
-
for (const
|
|
446
|
-
re.scene.remove(
|
|
532
|
+
setPlates: (a, l, U, Y) => {
|
|
533
|
+
const re = ce.current;
|
|
534
|
+
w.current = l, S.current = U, j.current = a, p.current = Y;
|
|
535
|
+
for (const we of re.plateBeds || []) for (const _e of [we.gridThin, we.gridBold, we.border])
|
|
536
|
+
re.scene.remove(_e), _e.geometry.dispose(), _e.material.dispose();
|
|
447
537
|
re.plateBeds = [];
|
|
448
|
-
const
|
|
449
|
-
for (let
|
|
450
|
-
for (let
|
|
451
|
-
const
|
|
452
|
-
const
|
|
453
|
-
return
|
|
538
|
+
const X = Ft(a), ke = rt(l), ze = rt(U), Ce = Math.min(l, U), be = Ce >= 6e3 ? 100 : Ce >= 1200 ? 50 : Ce >= 600 ? 20 : 10, Se = [], Ve = [], ot = -l / 2, Ue = -U / 2;
|
|
539
|
+
for (let we = 0, _e = ot; _e <= l / 2 + 1e-6; _e = ot + ++we * be) (we % 5 ? Se : Ve).push(_e, 0, Ue, _e, 0, U / 2);
|
|
540
|
+
for (let we = 0, _e = Ue; _e <= U / 2 + 1e-6; _e = Ue + ++we * be) (we % 5 ? Se : Ve).push(ot, 0, _e, l / 2, 0, _e);
|
|
541
|
+
const lt = (we) => {
|
|
542
|
+
const _e = new W.BufferGeometry();
|
|
543
|
+
return _e.setAttribute("position", new W.Float32BufferAttribute(we, 3)), _e;
|
|
454
544
|
};
|
|
455
|
-
for (let
|
|
456
|
-
const
|
|
457
|
-
|
|
458
|
-
const
|
|
459
|
-
|
|
545
|
+
for (let we = 0; we < a; we++) {
|
|
546
|
+
const _e = we % X * ke, Le = Math.floor(we / X) * ze, Ie = new W.LineSegments(lt(Se), new W.LineBasicMaterial({ color: 2304561 })), We = new W.LineSegments(lt(Ve), new W.LineBasicMaterial({ color: 3752781 }));
|
|
547
|
+
Ie.position.set(_e, 0, Le), We.position.set(_e, 0, Le), re.scene.add(Ie), re.scene.add(We);
|
|
548
|
+
const Qe = we === Y, Ye = new W.LineSegments(new W.EdgesGeometry(new W.PlaneGeometry(l, U)), new W.LineBasicMaterial({ color: Qe ? 44610 : 4871520, linewidth: Qe ? 2 : 1 }));
|
|
549
|
+
Ye.rotation.x = -Math.PI / 2, Ye.position.set(_e, 0, Le), re.scene.add(Ye), re.plateBeds.push({ gridThin: Ie, gridBold: We, border: Ye });
|
|
460
550
|
}
|
|
461
551
|
},
|
|
462
|
-
setBed: (
|
|
463
|
-
var
|
|
464
|
-
(
|
|
552
|
+
setBed: (a, l) => {
|
|
553
|
+
var U;
|
|
554
|
+
(U = r.current) == null || U.setPlates(j.current, a, l, p.current);
|
|
465
555
|
}
|
|
466
556
|
// backwards compatible
|
|
467
557
|
};
|
|
468
|
-
const
|
|
469
|
-
var
|
|
470
|
-
(
|
|
558
|
+
const bt = (a) => {
|
|
559
|
+
var l;
|
|
560
|
+
(l = i.current) == null || l.call(i, a), q();
|
|
471
561
|
};
|
|
472
|
-
window.addEventListener("keydown",
|
|
473
|
-
const
|
|
474
|
-
|
|
562
|
+
window.addEventListener("keydown", bt);
|
|
563
|
+
const gt = new ResizeObserver(() => {
|
|
564
|
+
C = y.clientWidth || C, V = y.clientHeight || V, O.aspect = C / V, O.updateProjectionMatrix(), f.setSize(C, V), q();
|
|
475
565
|
});
|
|
476
|
-
|
|
477
|
-
let
|
|
478
|
-
const
|
|
479
|
-
|
|
566
|
+
gt.observe(y), K(je());
|
|
567
|
+
let yt = 0, xt = 0;
|
|
568
|
+
const jt = (a = 0) => {
|
|
569
|
+
yt = requestAnimationFrame(jt), $.update(), (G || a - xt > 500) && (G = !1, xt = a, f.render(N, O));
|
|
480
570
|
};
|
|
481
|
-
return
|
|
482
|
-
cancelAnimationFrame(
|
|
483
|
-
|
|
484
|
-
}),
|
|
571
|
+
return jt(), () => {
|
|
572
|
+
cancelAnimationFrame(yt), gt.disconnect(), window.removeEventListener("keydown", bt), f.domElement.removeEventListener("pointermove", qe), f.domElement.removeEventListener("pointerdown", dt), f.domElement.removeEventListener("pointerdown", Mt), f.domElement.removeEventListener("contextmenu", At), f.domElement.removeEventListener("dblclick", Je), f.domElement.removeEventListener("wheel", Nt, { capture: !0 }), window.removeEventListener("pointerup", Xe), window.removeEventListener("pointercancel", Xe), r.current = null, P.detach(), P.dispose(), $.dispose(), N.traverse((a) => {
|
|
573
|
+
a.geometry && a.geometry.dispose(), a.material && a.material.dispose();
|
|
574
|
+
}), f.dispose(), f.domElement.parentNode && f.domElement.parentNode.removeChild(f.domElement);
|
|
485
575
|
};
|
|
486
|
-
}, []), { mountRef:
|
|
576
|
+
}, []), { mountRef: F, three: ce };
|
|
487
577
|
}
|
|
488
|
-
function
|
|
578
|
+
function Qa(t) {
|
|
489
579
|
const {
|
|
490
|
-
settings:
|
|
580
|
+
settings: r,
|
|
491
581
|
wipeTowerReal: c,
|
|
492
|
-
workerRef:
|
|
493
|
-
apiRef:
|
|
494
|
-
layersDataRef:
|
|
495
|
-
layerLoRef:
|
|
496
|
-
layerHiRef:
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
}, y = () => {
|
|
513
|
-
|
|
514
|
-
|
|
582
|
+
workerRef: i,
|
|
583
|
+
apiRef: o,
|
|
584
|
+
layersDataRef: p,
|
|
585
|
+
layerLoRef: h,
|
|
586
|
+
layerHiRef: j,
|
|
587
|
+
paintStateCountsRef: x,
|
|
588
|
+
rebuildToolpaths: B,
|
|
589
|
+
rebuildPaintOverlay: z,
|
|
590
|
+
setProgress: m,
|
|
591
|
+
setSlicing: L,
|
|
592
|
+
setError: D,
|
|
593
|
+
setStats: R,
|
|
594
|
+
setOverBed: K,
|
|
595
|
+
setLayerCount: J,
|
|
596
|
+
setLayerLo: _,
|
|
597
|
+
setLayerHi: T,
|
|
598
|
+
setGcodeUrl: F,
|
|
599
|
+
setCanvasMode: ce,
|
|
600
|
+
setPaintCounts: pe,
|
|
601
|
+
setSliceNotice: w
|
|
602
|
+
} = t, S = ne(null), E = ne(null), M = ne(!1), y = ne(null), v = ne(null), C = ne(0), V = () => {
|
|
603
|
+
C.current && (clearInterval(C.current), C.current = 0);
|
|
604
|
+
}, f = () => {
|
|
605
|
+
const s = v.current;
|
|
606
|
+
if (console.info("[vp-cancel] cancelSlice, hasView=", !!(s != null && s.cancel)), s != null && s.cancel)
|
|
515
607
|
try {
|
|
516
|
-
Atomics.store(
|
|
608
|
+
Atomics.store(s.cancel, 0, 1);
|
|
517
609
|
} catch {
|
|
518
|
-
|
|
610
|
+
s.cancel[0] = 1;
|
|
519
611
|
}
|
|
520
|
-
},
|
|
521
|
-
const
|
|
522
|
-
return
|
|
523
|
-
},
|
|
524
|
-
const
|
|
525
|
-
|
|
526
|
-
const
|
|
527
|
-
|
|
612
|
+
}, N = (s, d) => {
|
|
613
|
+
const A = d > 2 ? (d - 2) / 2 : 0;
|
|
614
|
+
return A ? s <= A ? 0.35 * (s / A) : s === A + 1 ? 0.36 : s === A + 2 ? 0.87 : 0.87 + 0.13 * ((s - A - 2) / A) : d ? s / d : 0;
|
|
615
|
+
}, O = (s) => {
|
|
616
|
+
const d = v.current;
|
|
617
|
+
d && (V(), C.current = setInterval(() => {
|
|
618
|
+
const A = d.arr[0];
|
|
619
|
+
m(0.36 + 0.51 * Math.min(0.95, A / (3.5 * s)));
|
|
528
620
|
}, 150));
|
|
529
|
-
},
|
|
530
|
-
const
|
|
531
|
-
|
|
532
|
-
|
|
621
|
+
}, H = () => {
|
|
622
|
+
const s = v.current;
|
|
623
|
+
s && (V(), C.current = setInterval(() => {
|
|
624
|
+
m(0.35 * Math.min(1, s.arr[0] / 1e3));
|
|
533
625
|
}, 150));
|
|
534
626
|
};
|
|
535
627
|
function oe() {
|
|
536
|
-
if (!
|
|
537
|
-
const
|
|
538
|
-
|
|
539
|
-
var
|
|
540
|
-
const
|
|
541
|
-
if (
|
|
542
|
-
const
|
|
543
|
-
|
|
544
|
-
} else if (
|
|
628
|
+
if (!i.current) {
|
|
629
|
+
const s = xa();
|
|
630
|
+
s.onmessage = (A) => {
|
|
631
|
+
var se, ye, xe, je, Q;
|
|
632
|
+
const u = A.data, I = S.current;
|
|
633
|
+
if (u.type === "progress") {
|
|
634
|
+
const Z = u.total > 2 ? (u.total - 2) / 2 : 0;
|
|
635
|
+
Z && u.done <= Z && V(), Z && u.done === Z + 1 && O(Z), Z && u.done >= Z + 2 && V(), m(N(u.done, u.total)), (se = I == null ? void 0 : I.note) == null || se.call(I, u.done, u.total), (ye = I == null ? void 0 : I.kick) == null || ye.call(I);
|
|
636
|
+
} else if (u.type === "supsab")
|
|
545
637
|
try {
|
|
546
|
-
|
|
547
|
-
} catch (
|
|
548
|
-
console.info("[vp-cancel] supsab view fail",
|
|
638
|
+
v.current = { arr: new Uint32Array(u.buf, u.ptr, 1), cancel: u.cancelPtr ? new Uint32Array(u.buf, u.cancelPtr, 1) : null }, console.info("[vp-cancel] supsab cancelPtr=", u.cancelPtr);
|
|
639
|
+
} catch (Z) {
|
|
640
|
+
console.info("[vp-cancel] supsab view fail", Z);
|
|
549
641
|
}
|
|
550
|
-
else if (
|
|
551
|
-
(
|
|
552
|
-
const
|
|
553
|
-
|
|
554
|
-
} else
|
|
642
|
+
else if (u.type === "layer") {
|
|
643
|
+
(xe = I == null ? void 0 : I.kick) == null || xe.call(I);
|
|
644
|
+
const Z = E.current;
|
|
645
|
+
Z && (Z.layers.push({ z: u.z, paths: u.paths, widths: u.widths }), u.gcode && Z.gcode.push(u.gcode));
|
|
646
|
+
} else u.type === "done" ? (V(), I ? (S.current = null, (je = I.stop) == null || je.call(I), I.resolve(ue(u.result))) : ($(ue(u.result)), L(!1))) : u.type === "error" ? (V(), I ? (S.current = null, (Q = I.stop) == null || Q.call(I), I.reject(new Error(u.error))) : (D("Slice failed: " + u.error), L(!1))) : u.type === "prepared" || (u.type === "painted" ? pe({ enf: u.enf, blk: u.blk }) : u.type === "overlay" && z(u.enf, u.blk, u.overlays));
|
|
555
647
|
};
|
|
556
|
-
const
|
|
557
|
-
var
|
|
558
|
-
if (
|
|
559
|
-
|
|
560
|
-
const
|
|
561
|
-
if (
|
|
562
|
-
|
|
648
|
+
const d = (A) => {
|
|
649
|
+
var I;
|
|
650
|
+
if (i.current !== s) return;
|
|
651
|
+
V(), v.current = null;
|
|
652
|
+
const u = S.current;
|
|
653
|
+
if (u) {
|
|
654
|
+
S.current = null, (I = u.stop) == null || I.call(u);
|
|
563
655
|
try {
|
|
564
|
-
|
|
656
|
+
s.terminate();
|
|
565
657
|
} catch {
|
|
566
658
|
}
|
|
567
|
-
|
|
659
|
+
i.current = null, u.reject(new Error(A));
|
|
568
660
|
} else
|
|
569
|
-
|
|
661
|
+
D(A), L(!1);
|
|
570
662
|
};
|
|
571
|
-
|
|
663
|
+
s.onerror = (A) => d("Worker terminated (likely out of memory): " + (A.message || "worker error")), s.onmessageerror = () => d("Worker message error (structured clone failed)"), i.current = s, typeof window < "u" && (window.__vpWorker = s);
|
|
572
664
|
}
|
|
573
|
-
return
|
|
665
|
+
return i.current;
|
|
574
666
|
}
|
|
575
|
-
function
|
|
576
|
-
if (
|
|
577
|
-
const
|
|
578
|
-
return { stats:
|
|
667
|
+
function ue(s) {
|
|
668
|
+
if (s && s.stats && s.stats.streamed) {
|
|
669
|
+
const d = E.current || { layers: [], gcode: [] };
|
|
670
|
+
return { stats: s.stats, layers: d.layers, gcode: d.gcode.join("") };
|
|
579
671
|
}
|
|
580
|
-
return
|
|
672
|
+
return s;
|
|
581
673
|
}
|
|
582
|
-
function
|
|
583
|
-
var
|
|
584
|
-
if (
|
|
585
|
-
|
|
674
|
+
function $(s) {
|
|
675
|
+
var A;
|
|
676
|
+
if (s.error) {
|
|
677
|
+
D(String(s.error));
|
|
586
678
|
return;
|
|
587
679
|
}
|
|
588
|
-
|
|
589
|
-
const
|
|
590
|
-
|
|
591
|
-
layers:
|
|
592
|
-
segments:
|
|
593
|
-
filament:
|
|
594
|
-
timeSec:
|
|
595
|
-
engine:
|
|
596
|
-
limits:
|
|
597
|
-
}),
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
}, []),
|
|
680
|
+
p.current = s.layers;
|
|
681
|
+
const d = s.layers.length;
|
|
682
|
+
h.current = 0, j.current = d - 1, _(0), T(d - 1), B(), (A = o.current) == null || A.onSliced(), ce("preview"), R({
|
|
683
|
+
layers: s.stats.layers,
|
|
684
|
+
segments: s.stats.path_segments,
|
|
685
|
+
filament: s.stats.filament_mm,
|
|
686
|
+
timeSec: s.stats.time_estimate,
|
|
687
|
+
engine: s.stats.time_engine,
|
|
688
|
+
limits: s.stats.machine_limits
|
|
689
|
+
}), K(!!s.stats.over_bed), J(d), F((u) => (u && URL.revokeObjectURL(u), URL.createObjectURL(new Blob([s.gcode], { type: "text/plain" }))));
|
|
690
|
+
}
|
|
691
|
+
Te(() => () => {
|
|
692
|
+
i.current && (i.current.terminate(), i.current = null);
|
|
693
|
+
}, []), Te(() => {
|
|
602
694
|
try {
|
|
603
695
|
oe().postMessage({ cmd: "warmup" });
|
|
604
696
|
} catch {
|
|
605
697
|
}
|
|
606
698
|
}, []);
|
|
607
|
-
const
|
|
608
|
-
function
|
|
609
|
-
return new Promise((
|
|
699
|
+
const P = 6e4, ve = 3e5;
|
|
700
|
+
function Me(s, d) {
|
|
701
|
+
return new Promise((A, u) => {
|
|
610
702
|
if (typeof window < "u" && window.__vpFail && window.__vpFail(window.__vpSliceN = (window.__vpSliceN || 0) + 1)) {
|
|
611
|
-
|
|
703
|
+
u(new Error("forced failure (test hook)"));
|
|
612
704
|
return;
|
|
613
705
|
}
|
|
614
|
-
const
|
|
615
|
-
|
|
616
|
-
let
|
|
617
|
-
const
|
|
618
|
-
let
|
|
619
|
-
const
|
|
620
|
-
|
|
621
|
-
const
|
|
622
|
-
|
|
623
|
-
},
|
|
624
|
-
const
|
|
625
|
-
return
|
|
626
|
-
},
|
|
627
|
-
|
|
628
|
-
},
|
|
629
|
-
|
|
630
|
-
const
|
|
631
|
-
|
|
632
|
-
var
|
|
633
|
-
|
|
706
|
+
const I = typeof window < "u" && window.__vpStallNext ? (window.__vpStallNext = !1, !0) : !1, se = typeof window < "u" && window.__vpWatchdogOnce ? ((le) => (window.__vpWatchdogOnce = 0, le))(window.__vpWatchdogOnce) : P;
|
|
707
|
+
E.current = { layers: [], gcode: [] };
|
|
708
|
+
let ye = 0, xe = 0, je = 0;
|
|
709
|
+
const Q = performance.now();
|
|
710
|
+
let Z = "";
|
|
711
|
+
const ee = (le, Ae) => {
|
|
712
|
+
xe = le, je = Ae;
|
|
713
|
+
const Pe = Ae > 2 ? (Ae - 2) / 2 : 0, Re = Pe ? le < Pe ? "PASS1…" : le === Pe ? "PASS1-done" : le === Pe + 1 ? "surf-done" : le === Pe + 2 ? "support-done" : le === Ae ? "emit-done" : "emit…" : "";
|
|
714
|
+
Re && Re !== Z && (console.info(`[vp-prof] ${Re} +${((performance.now() - Q) / 1e3).toFixed(1)}s`), Z = Re);
|
|
715
|
+
}, he = () => {
|
|
716
|
+
const le = je > 2 ? (je - 2) / 2 : 0;
|
|
717
|
+
return le && xe >= le && xe < le + 2 ? ve : se;
|
|
718
|
+
}, me = () => {
|
|
719
|
+
ye && (clearTimeout(ye), ye = 0);
|
|
720
|
+
}, fe = () => {
|
|
721
|
+
me();
|
|
722
|
+
const le = he();
|
|
723
|
+
ye = setTimeout(() => {
|
|
724
|
+
var Ae;
|
|
725
|
+
S.current = null, V(), v.current = null;
|
|
634
726
|
try {
|
|
635
|
-
(
|
|
727
|
+
(Ae = i.current) == null || Ae.terminate();
|
|
636
728
|
} catch {
|
|
637
729
|
}
|
|
638
|
-
|
|
639
|
-
},
|
|
730
|
+
i.current = null, u(new Error(`watchdog: no progress for ${le}ms — assuming memory pressure`));
|
|
731
|
+
}, le);
|
|
640
732
|
};
|
|
641
|
-
|
|
733
|
+
S.current = { resolve: A, reject: u, kick: fe, stop: me, note: ee }, fe(), oe().postMessage({ stl: s, params: d, stall: I }), H();
|
|
642
734
|
});
|
|
643
735
|
}
|
|
644
|
-
function
|
|
645
|
-
var
|
|
736
|
+
function ge() {
|
|
737
|
+
var s;
|
|
646
738
|
try {
|
|
647
|
-
(
|
|
739
|
+
(s = i.current) == null || s.terminate();
|
|
648
740
|
} catch {
|
|
649
741
|
}
|
|
650
|
-
|
|
742
|
+
i.current = null, oe();
|
|
651
743
|
}
|
|
652
|
-
async function
|
|
653
|
-
const
|
|
744
|
+
async function Ee(s, d) {
|
|
745
|
+
const A = (u) => String((u == null ? void 0 : u.message) || u).includes("canceled");
|
|
654
746
|
try {
|
|
655
|
-
const
|
|
656
|
-
return { r:
|
|
657
|
-
} catch (
|
|
658
|
-
if (
|
|
659
|
-
if (
|
|
660
|
-
|
|
747
|
+
const u = await Me(s, JSON.stringify(d));
|
|
748
|
+
return { r: u, economy: !!(u.stats && u.stats.economy) };
|
|
749
|
+
} catch (u) {
|
|
750
|
+
if (A(u)) throw u;
|
|
751
|
+
if (d.wall_generator !== "classic") {
|
|
752
|
+
ge();
|
|
661
753
|
try {
|
|
662
|
-
const
|
|
663
|
-
return { r:
|
|
664
|
-
} catch (
|
|
665
|
-
if (
|
|
754
|
+
const se = await Me(s, JSON.stringify({ ...d, wall_generator: "classic", keep_stages: !1, reuse_stages: 0 }));
|
|
755
|
+
return { r: se, economy: !!(se.stats && se.stats.economy), classicWalls: !0 };
|
|
756
|
+
} catch (se) {
|
|
757
|
+
if (A(se)) throw se;
|
|
666
758
|
}
|
|
667
759
|
}
|
|
668
|
-
return
|
|
760
|
+
return ge(), { r: await Me(s, JSON.stringify({ ...d, economy: !0, keep_stages: !1, reuse_stages: 0 })), economy: !0, recovered: !0 };
|
|
669
761
|
}
|
|
670
762
|
}
|
|
671
|
-
async function
|
|
763
|
+
async function b(s) {
|
|
672
764
|
try {
|
|
673
|
-
const
|
|
674
|
-
return Array.from(new Uint8Array(
|
|
765
|
+
const d = await crypto.subtle.digest("SHA-256", s);
|
|
766
|
+
return Array.from(new Uint8Array(d, 0, 8)).map((A) => A.toString(16).padStart(2, "0")).join("");
|
|
675
767
|
} catch {
|
|
676
768
|
return null;
|
|
677
769
|
}
|
|
678
770
|
}
|
|
679
|
-
function
|
|
680
|
-
|
|
771
|
+
function k(s, d) {
|
|
772
|
+
s.economy || (s.keep_stages = !0, s.reuse_stages = d && d === y.current ? 2 : 0);
|
|
681
773
|
}
|
|
682
|
-
function
|
|
683
|
-
|
|
684
|
-
|
|
774
|
+
function G(s) {
|
|
775
|
+
var Z;
|
|
776
|
+
const d = ln(r);
|
|
777
|
+
s.extruders >= 2 && s.split > 0 && (d.extruder_count = s.extruders, d.mm_group_split = s.split, (Z = s.splits) != null && Z.length && (d.mm_group_splits = s.splits, d.mm_group_tools = s.tools), d.wipe_tower_real = c);
|
|
778
|
+
const A = Object.entries((x == null ? void 0 : x.current) ?? {}).filter(([, ee]) => ee > 0).map(([ee]) => Number(ee)), u = A.length ? Math.max(...A) : 0;
|
|
779
|
+
u >= 2 && (d.extruder_count = Math.max(d.extruder_count ?? 1, u), d.wipe_tower_real = c);
|
|
780
|
+
const I = (ee) => {
|
|
781
|
+
const he = He(r, ee), me = Array.isArray(he) ? he : he == null || he === "" ? [] : [he];
|
|
782
|
+
return me.length ? me : void 0;
|
|
783
|
+
}, se = (ee) => ee && ee.map((he) => {
|
|
784
|
+
const me = parseFloat(he);
|
|
785
|
+
return Number.isFinite(me) ? me : 0;
|
|
786
|
+
}), ye = I("filament_type"), xe = I("filament_settings_id"), je = se(I("filament_density")), Q = se(I("filament_cost"));
|
|
787
|
+
if (ye && (d.filament_type = ye), xe && (d.filament_settings_id = xe), je && (d.filament_density = je), Q && (d.filament_cost = Q), d.gcode_stats_block = !0, d.gcode_config_block = !0, (d.extruder_count ?? 1) >= 2 && Number.isFinite(s.minX) && d.prime_tower_x == null) {
|
|
788
|
+
const ee = d.wipe_tower_real ?? !0 ? d.prime_tower_width ?? 30 : 15, he = 5, me = d.bed_width ?? 200, fe = d.bed_depth ?? 200, le = s.minX + me / 2, Ae = (s.minY + s.maxY) / 2 + fe / 2;
|
|
789
|
+
d.prime_tower_x = Math.min(Math.max(le - he - ee, 1), me - ee - 1), d.prime_tower_y = Math.min(Math.max(Ae - ee / 2, 1), fe - ee - 1);
|
|
790
|
+
}
|
|
791
|
+
return A.length && (d.enable_support && A.includes(2) ? w == null || w("Support is on and T2 is painted. One facet carries one mark, and a support blocker is the same mark as T2 — the painted areas were sliced as T2, not as blocked support.") : u < 2 && (w == null || w("Only T1 was painted. T1 is the default extruder every unpainted facet already uses, so the slice is unchanged — paint T2 or higher to get a second material."))), M.current && (d.sparse_infill_pattern = "rectilinear", d.infill_density = Math.min(d.infill_density ?? 0.15, 0.08), d.economy = !0), typeof window < "u" && window.__vpForceTree && (d.enable_support = !0, d.support_style = "tree", d.support_threshold_angle = 40), typeof window < "u" && (window.__vpParams = d), d;
|
|
685
792
|
}
|
|
686
|
-
async function
|
|
687
|
-
const
|
|
688
|
-
|
|
793
|
+
async function q(s) {
|
|
794
|
+
const d = G(s), A = await b(s.buf);
|
|
795
|
+
k(d, A);
|
|
689
796
|
try {
|
|
690
|
-
const
|
|
691
|
-
return
|
|
692
|
-
} catch (
|
|
693
|
-
throw
|
|
797
|
+
const u = await Ee(s.buf, d);
|
|
798
|
+
return y.current = u.economy || u.classicWalls ? null : A, { ...u, params: d };
|
|
799
|
+
} catch (u) {
|
|
800
|
+
throw y.current = null, u;
|
|
694
801
|
}
|
|
695
802
|
}
|
|
696
|
-
return { getWorker: oe, cancelSlice:
|
|
803
|
+
return { getWorker: oe, cancelSlice: f, runSlice: q, pendingSliceRef: S, downgradeRef: M };
|
|
697
804
|
}
|
|
698
|
-
function
|
|
805
|
+
function eo(t) {
|
|
699
806
|
const {
|
|
700
|
-
three:
|
|
807
|
+
three: r,
|
|
701
808
|
plateTpRef: c,
|
|
702
|
-
toolpathRef:
|
|
703
|
-
segDataRef:
|
|
704
|
-
layersDataRef:
|
|
705
|
-
plateResultsRef:
|
|
706
|
-
plateOffsetsRef:
|
|
707
|
-
lineWidthRef:
|
|
708
|
-
showTravelRef:
|
|
709
|
-
viewTypeRef:
|
|
710
|
-
layerLoRef:
|
|
711
|
-
layerHiRef:
|
|
712
|
-
selectedPlateRef:
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
function _() {
|
|
724
|
-
for (const f of Object.keys(c.current)) u(Number(f));
|
|
725
|
-
l.current = null, r.current = null;
|
|
726
|
-
}
|
|
727
|
-
function G(f, g) {
|
|
728
|
-
const { toolpathGroup: y } = a.current;
|
|
729
|
-
if (!y || (u(f), !g || !g.length)) return null;
|
|
730
|
-
const v = qn(g, b.current), D = Wn(N, v), W = w.current[f] || { offX: 0, offZ: 0 }, oe = new N.Group();
|
|
731
|
-
oe.rotation.x = -Math.PI / 2, oe.position.set(W.offX || 0, 0, W.offZ || 0), oe.add(D.mesh), oe.add(D.travLines), y.add(oe), D.setTravelVisible(T.current), D.setLayerRange(0, Math.max(0, g.length - 1));
|
|
732
|
-
const ge = Dt(v, P.current, h());
|
|
733
|
-
D.setColors(ge.color);
|
|
734
|
-
const de = { group: oe, ctl: D, seg: v, layers: g };
|
|
735
|
-
return c.current[f] = de, de;
|
|
809
|
+
toolpathRef: i,
|
|
810
|
+
segDataRef: o,
|
|
811
|
+
layersDataRef: p,
|
|
812
|
+
plateResultsRef: h,
|
|
813
|
+
plateOffsetsRef: j,
|
|
814
|
+
lineWidthRef: x,
|
|
815
|
+
showTravelRef: B,
|
|
816
|
+
viewTypeRef: z,
|
|
817
|
+
layerLoRef: m,
|
|
818
|
+
layerHiRef: L,
|
|
819
|
+
selectedPlateRef: D,
|
|
820
|
+
extruderColorsRef: R,
|
|
821
|
+
settings: K,
|
|
822
|
+
setSegCount: J,
|
|
823
|
+
setColorRange: _,
|
|
824
|
+
setRoleLegend: T
|
|
825
|
+
} = t;
|
|
826
|
+
function F(v) {
|
|
827
|
+
var V;
|
|
828
|
+
const C = c.current[v];
|
|
829
|
+
C && (C.group.remove(C.ctl.mesh), C.group.remove(C.ctl.travLines), C.ctl.dispose(), (V = r.current.toolpathGroup) == null || V.remove(C.group), delete c.current[v], i.current === C.ctl && (i.current = null, o.current = null));
|
|
736
830
|
}
|
|
737
|
-
function
|
|
738
|
-
for (const
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
const
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
831
|
+
function ce() {
|
|
832
|
+
for (const v of Object.keys(c.current)) F(Number(v));
|
|
833
|
+
i.current = null, o.current = null;
|
|
834
|
+
}
|
|
835
|
+
function pe(v, C) {
|
|
836
|
+
const { toolpathGroup: V } = r.current;
|
|
837
|
+
if (!V || (F(v), !C || !C.length)) return null;
|
|
838
|
+
const f = va(C, x.current), N = wa(W, f), O = j.current[v] || { offX: 0, offZ: 0 }, H = new W.Group();
|
|
839
|
+
H.rotation.x = -Math.PI / 2, H.position.set(O.offX || 0, 0, O.offZ || 0), H.add(N.mesh), H.add(N.travLines), V.add(H), N.setTravelVisible(B.current), N.setLayerRange(0, Math.max(0, C.length - 1));
|
|
840
|
+
const oe = Wn(f, z.current, S());
|
|
841
|
+
N.setColors(oe.color);
|
|
842
|
+
const ue = { group: H, ctl: N, seg: f, layers: C };
|
|
843
|
+
return c.current[v] = ue, ue;
|
|
844
|
+
}
|
|
845
|
+
function w() {
|
|
846
|
+
for (const [v, C] of Object.entries(h.current)) {
|
|
847
|
+
const V = Number(v);
|
|
848
|
+
if (!C || C.error || !C.layers || !C.layers.length) continue;
|
|
849
|
+
const f = c.current[V];
|
|
850
|
+
(!f || f.layers !== C.layers) && pe(V, C.layers);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
function S() {
|
|
854
|
+
const v = (V, f) => {
|
|
855
|
+
const N = He(K, V), O = parseFloat(N);
|
|
856
|
+
return Number.isFinite(O) ? O : f;
|
|
857
|
+
}, C = v("outer_wall_speed", 60);
|
|
750
858
|
return {
|
|
859
|
+
// The filament palette, so the Filament view can paint each tool in its own colour rather than a stand-in.
|
|
860
|
+
toolColors: (R == null ? void 0 : R.current) ?? [],
|
|
751
861
|
speedByType: {
|
|
752
|
-
1:
|
|
753
|
-
2:
|
|
754
|
-
3:
|
|
755
|
-
4:
|
|
756
|
-
5:
|
|
757
|
-
6:
|
|
758
|
-
7:
|
|
759
|
-
8:
|
|
760
|
-
9:
|
|
761
|
-
10:
|
|
762
|
-
11:
|
|
862
|
+
1: C,
|
|
863
|
+
2: v("sparse_infill_speed", 40),
|
|
864
|
+
3: v("internal_solid_infill_speed", 45),
|
|
865
|
+
4: C,
|
|
866
|
+
5: v("support_speed", 35),
|
|
867
|
+
6: v("support_speed", 35),
|
|
868
|
+
7: v("gap_infill_speed", 30),
|
|
869
|
+
8: C,
|
|
870
|
+
9: v("bridge_speed", 25),
|
|
871
|
+
10: v("ironing_speed", 20),
|
|
872
|
+
11: C
|
|
763
873
|
},
|
|
764
|
-
firstLayerSpeed:
|
|
765
|
-
closeFanLayers:
|
|
766
|
-
fanNormal:
|
|
767
|
-
tempNormal:
|
|
768
|
-
tempFirst:
|
|
874
|
+
firstLayerSpeed: v("initial_layer_speed", 30),
|
|
875
|
+
closeFanLayers: v("close_fan_the_first_x_layers", 1),
|
|
876
|
+
fanNormal: v("fan_max_speed", 100),
|
|
877
|
+
tempNormal: v("nozzle_temperature", 210),
|
|
878
|
+
tempFirst: v("nozzle_temperature_initial_layer", v("nozzle_temperature", 210))
|
|
769
879
|
};
|
|
770
880
|
}
|
|
771
881
|
function E() {
|
|
772
|
-
const
|
|
773
|
-
for (const
|
|
774
|
-
const
|
|
775
|
-
|
|
882
|
+
const v = S();
|
|
883
|
+
for (const C of Object.values(c.current)) {
|
|
884
|
+
const V = Wn(C.seg, z.current, v);
|
|
885
|
+
C.ctl.setColors(V.color), C.ctl === i.current && _({ min: V.min, max: V.max, label: V.label, unit: V.unit, cont: V.cont });
|
|
776
886
|
}
|
|
777
887
|
}
|
|
778
|
-
function
|
|
779
|
-
const
|
|
780
|
-
if (!
|
|
781
|
-
|
|
888
|
+
function M() {
|
|
889
|
+
const v = D.current, C = p.current || [];
|
|
890
|
+
if (!C.length) {
|
|
891
|
+
F(v), J(0), i.current = null, o.current = null;
|
|
782
892
|
return;
|
|
783
893
|
}
|
|
784
|
-
const
|
|
785
|
-
if (!
|
|
786
|
-
|
|
894
|
+
const V = pe(v, C);
|
|
895
|
+
if (!V) {
|
|
896
|
+
J(0);
|
|
787
897
|
return;
|
|
788
898
|
}
|
|
789
|
-
|
|
899
|
+
i.current = V.ctl, o.current = V.seg, V.ctl.setLayerRange(m.current, L.current), E(), J(V.seg.nSeg), T(er(V.seg.typeLengths));
|
|
790
900
|
}
|
|
791
|
-
function
|
|
792
|
-
var
|
|
793
|
-
(
|
|
901
|
+
function y() {
|
|
902
|
+
var v;
|
|
903
|
+
(v = i.current) == null || v.setLayerRange(m.current, L.current);
|
|
794
904
|
}
|
|
795
|
-
return { disposePlateToolpath:
|
|
905
|
+
return { disposePlateToolpath: F, clearToolpaths: ce, buildPlateToolpath: pe, ensurePlateToolpaths: w, viewCtx: S, applyViewColors: E, rebuildToolpaths: M, applyLayerRange: y };
|
|
796
906
|
}
|
|
797
|
-
function
|
|
907
|
+
function to(t) {
|
|
798
908
|
const {
|
|
799
|
-
apiRef:
|
|
909
|
+
apiRef: r,
|
|
800
910
|
selectedPlateRef: c,
|
|
801
|
-
plateCountRef:
|
|
802
|
-
placeXRef:
|
|
803
|
-
plateResultsRef:
|
|
804
|
-
plateOffsetsRef:
|
|
805
|
-
plateTpRef:
|
|
806
|
-
layersDataRef:
|
|
807
|
-
toolpathRef:
|
|
808
|
-
segDataRef:
|
|
809
|
-
layerLoRef:
|
|
810
|
-
layerHiRef:
|
|
811
|
-
lineWidthRef:
|
|
812
|
-
downgradeRef:
|
|
813
|
-
settings:
|
|
814
|
-
canvasMode:
|
|
815
|
-
downgradeOffer:
|
|
816
|
-
runSlice:
|
|
817
|
-
ensurePlateToolpaths:
|
|
818
|
-
buildPlateToolpath:
|
|
819
|
-
applyViewColors:
|
|
820
|
-
disposePlateToolpath:
|
|
821
|
-
setStats:
|
|
822
|
-
setOverBed:
|
|
823
|
-
setLayerCount:
|
|
824
|
-
setSegCount:
|
|
825
|
-
setColorRange:
|
|
826
|
-
setRoleLegend:
|
|
827
|
-
setGcodeUrl:
|
|
828
|
-
setLayerLo:
|
|
829
|
-
setLayerHi:
|
|
830
|
-
setCanvasMode:
|
|
831
|
-
setSlicedPlateCount:
|
|
832
|
-
setSliceMenu:
|
|
833
|
-
setError:
|
|
834
|
-
setSliceNotice:
|
|
835
|
-
setDowngradeOffer:
|
|
836
|
-
setSlicing:
|
|
837
|
-
setProgress:
|
|
838
|
-
setPlateCount:
|
|
839
|
-
setSelectedPlate:
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
911
|
+
plateCountRef: i,
|
|
912
|
+
placeXRef: o,
|
|
913
|
+
plateResultsRef: p,
|
|
914
|
+
plateOffsetsRef: h,
|
|
915
|
+
plateTpRef: j,
|
|
916
|
+
layersDataRef: x,
|
|
917
|
+
toolpathRef: B,
|
|
918
|
+
segDataRef: z,
|
|
919
|
+
layerLoRef: m,
|
|
920
|
+
layerHiRef: L,
|
|
921
|
+
lineWidthRef: D,
|
|
922
|
+
downgradeRef: R,
|
|
923
|
+
settings: K,
|
|
924
|
+
canvasMode: J,
|
|
925
|
+
downgradeOffer: _,
|
|
926
|
+
runSlice: T,
|
|
927
|
+
ensurePlateToolpaths: F,
|
|
928
|
+
buildPlateToolpath: ce,
|
|
929
|
+
applyViewColors: pe,
|
|
930
|
+
disposePlateToolpath: w,
|
|
931
|
+
setStats: S,
|
|
932
|
+
setOverBed: E,
|
|
933
|
+
setLayerCount: M,
|
|
934
|
+
setSegCount: y,
|
|
935
|
+
setColorRange: v,
|
|
936
|
+
setRoleLegend: C,
|
|
937
|
+
setGcodeUrl: V,
|
|
938
|
+
setLayerLo: f,
|
|
939
|
+
setLayerHi: N,
|
|
940
|
+
setCanvasMode: O,
|
|
941
|
+
setSlicedPlateCount: H,
|
|
942
|
+
setSliceMenu: oe,
|
|
943
|
+
setError: ue,
|
|
944
|
+
setSliceNotice: $,
|
|
945
|
+
setDowngradeOffer: P,
|
|
946
|
+
setSlicing: ve,
|
|
947
|
+
setProgress: Me,
|
|
948
|
+
setPlateCount: ge,
|
|
949
|
+
setSelectedPlate: Ee,
|
|
950
|
+
syncPaintSelector: b,
|
|
951
|
+
onSlicedRef: k
|
|
952
|
+
} = t, G = (Q, Z) => {
|
|
953
|
+
var ee;
|
|
954
|
+
Z && !Z.error && ((ee = k == null ? void 0 : k.current) == null || ee.call(k, { plate: Q, stats: Z.stats, gcode: Z.gcode }));
|
|
955
|
+
};
|
|
956
|
+
function q(Q) {
|
|
957
|
+
var le;
|
|
958
|
+
F();
|
|
959
|
+
const Z = B.current;
|
|
960
|
+
Z && Z.setLayerRange(0, 1e9);
|
|
961
|
+
const ee = p.current[Q];
|
|
962
|
+
if (!ee || ee.error || !ee.layers || !ee.layers.length) {
|
|
963
|
+
x.current = null, B.current = null, z.current = null, S(null), E(!1), M(0), y(0), v(null), C([]), V((Ae) => (Ae && URL.revokeObjectURL(Ae), ""));
|
|
849
964
|
return;
|
|
850
965
|
}
|
|
851
|
-
|
|
852
|
-
const
|
|
853
|
-
|
|
854
|
-
const
|
|
855
|
-
|
|
856
|
-
layers:
|
|
857
|
-
segments:
|
|
858
|
-
filament:
|
|
859
|
-
timeSec:
|
|
860
|
-
engine:
|
|
861
|
-
limits:
|
|
862
|
-
}),
|
|
863
|
-
}
|
|
864
|
-
function
|
|
865
|
-
const
|
|
866
|
-
|
|
867
|
-
|
|
966
|
+
x.current = ee.layers;
|
|
967
|
+
const he = ee.layers.length;
|
|
968
|
+
m.current = 0, L.current = he - 1, f(0), N(he - 1);
|
|
969
|
+
const me = j.current[Q], fe = me && me.layers === ee.layers ? me : ce(Q, ee.layers);
|
|
970
|
+
fe && (B.current = fe.ctl, z.current = fe.seg, fe.ctl.setLayerRange(0, he - 1), pe(), y(fe.seg.nSeg), C(er(fe.seg.typeLengths))), (le = r.current) == null || le.onSliced(), O("preview"), S({
|
|
971
|
+
layers: ee.stats.layers,
|
|
972
|
+
segments: ee.stats.path_segments,
|
|
973
|
+
filament: ee.stats.filament_mm,
|
|
974
|
+
timeSec: ee.stats.time_estimate,
|
|
975
|
+
engine: ee.stats.time_engine,
|
|
976
|
+
limits: ee.stats.machine_limits
|
|
977
|
+
}), E(!!ee.stats.over_bed), M(he), V((Ae) => (Ae && URL.revokeObjectURL(Ae), URL.createObjectURL(new Blob([ee.gcode], { type: "text/plain" }))));
|
|
978
|
+
}
|
|
979
|
+
function s(Q, Z) {
|
|
980
|
+
const ee = URL.createObjectURL(new Blob([Q], { type: "text/plain" })), he = document.createElement("a");
|
|
981
|
+
he.href = ee, he.download = Z, he.style.display = "none", document.body.appendChild(he), he.click(), setTimeout(() => {
|
|
982
|
+
he.remove(), URL.revokeObjectURL(ee);
|
|
868
983
|
}, 4e3);
|
|
869
984
|
}
|
|
870
|
-
const
|
|
871
|
-
function
|
|
872
|
-
|
|
985
|
+
const d = (Q) => new Promise((Z) => setTimeout(Z, Q));
|
|
986
|
+
function A() {
|
|
987
|
+
H(Object.values(p.current).filter((Q) => Q && !Q.error && Q.gcode).length);
|
|
873
988
|
}
|
|
874
|
-
async function
|
|
875
|
-
|
|
876
|
-
const
|
|
877
|
-
if (!
|
|
878
|
-
|
|
989
|
+
async function u() {
|
|
990
|
+
oe(!1);
|
|
991
|
+
const Q = Object.entries(p.current).filter(([, Z]) => Z && !Z.error && Z.gcode).sort((Z, ee) => Number(Z[0]) - Number(ee[0]));
|
|
992
|
+
if (!Q.length) {
|
|
993
|
+
ue("No slice results to export — slice first");
|
|
879
994
|
return;
|
|
880
995
|
}
|
|
881
|
-
for (const [
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
}
|
|
885
|
-
async function
|
|
886
|
-
var
|
|
887
|
-
|
|
888
|
-
const
|
|
889
|
-
if (
|
|
890
|
-
|
|
891
|
-
let
|
|
892
|
-
const
|
|
893
|
-
for (let
|
|
894
|
-
const
|
|
895
|
-
if (
|
|
896
|
-
|
|
996
|
+
for (const [Z, ee] of Q)
|
|
997
|
+
s(ee.gcode, `plate_${Number(Z) + 1}.gcode`), await d(350);
|
|
998
|
+
$(`Exported G-code for ${Q.length} plate(s)`);
|
|
999
|
+
}
|
|
1000
|
+
async function I(Q = "current") {
|
|
1001
|
+
var ee, he;
|
|
1002
|
+
oe(!1), ue(""), $(""), P(null);
|
|
1003
|
+
const Z = c.current;
|
|
1004
|
+
if (D.current = ln(K).line_width, Q === "all") {
|
|
1005
|
+
ve(!0), Me(0);
|
|
1006
|
+
let me = 0, fe = !1, le = !1;
|
|
1007
|
+
const Ae = [];
|
|
1008
|
+
for (let Pe = 0; Pe < i.current; Pe++) {
|
|
1009
|
+
const Re = (ee = r.current) == null ? void 0 : ee.buildMergedSTL(Pe);
|
|
1010
|
+
if (Re) {
|
|
1011
|
+
Pe === c.current && (b == null || b(Re)), h.current[Pe] = { offX: Re.offX, offZ: Re.offZ };
|
|
897
1012
|
try {
|
|
898
|
-
const { r:
|
|
899
|
-
|
|
1013
|
+
const { r: qe, economy: dt, classicWalls: Xe } = await T(Re);
|
|
1014
|
+
p.current[Pe] = qe, A(), G(Pe, qe), me++, dt && (fe = !0), Xe && (le = !0);
|
|
900
1015
|
} catch {
|
|
901
|
-
|
|
1016
|
+
Ae.push(Pe + 1);
|
|
902
1017
|
}
|
|
903
1018
|
}
|
|
904
1019
|
}
|
|
905
|
-
if (
|
|
906
|
-
|
|
1020
|
+
if (ve(!1), !me) {
|
|
1021
|
+
P({ scope: "all" }), ue("All plates failed to slice (economy mode included) — try the simplified retry");
|
|
907
1022
|
return;
|
|
908
1023
|
}
|
|
909
|
-
|
|
1024
|
+
Ae.length ? ue(`Plate ${Ae.join(", ")} failed — the ${me} finished result(s) are kept (inspect/export from the tabs)`) : (ue(""), P(null)), fe ? $("Memory pressure — some plates finished in economy mode (no preview, G-code is fine)") : le && $("Arachne wall generation failed (degenerate geometry) — finished with classic walls (G-code is fine)"), q(p.current[Z] ? Z : Object.keys(p.current).map(Number)[0]);
|
|
910
1025
|
} else {
|
|
911
|
-
const
|
|
912
|
-
if (!
|
|
913
|
-
|
|
1026
|
+
const me = performance.now(), fe = (he = r.current) == null ? void 0 : he.buildMergedSTL(Z);
|
|
1027
|
+
if (!fe) {
|
|
1028
|
+
ue(`Plate ${Z + 1} has no objects`);
|
|
914
1029
|
return;
|
|
915
1030
|
}
|
|
916
|
-
console.info(`[vp-prof] buildMergedSTL ${(performance.now() -
|
|
1031
|
+
console.info(`[vp-prof] buildMergedSTL ${(performance.now() - me).toFixed(0)}ms (${(fe.buf.byteLength / 1048576).toFixed(1)}MB)`), Z === c.current && (b == null || b(fe)), h.current[Z] = { offX: fe.offX, offZ: fe.offZ }, ve(!0), Me(0);
|
|
917
1032
|
try {
|
|
918
|
-
const { r:
|
|
919
|
-
|
|
920
|
-
} catch (
|
|
921
|
-
if (
|
|
922
|
-
|
|
1033
|
+
const { r: le, economy: Ae, classicWalls: Pe, params: Re } = await T(fe);
|
|
1034
|
+
le != null && le.stats && console.info(`[vp-prof] kernel stages p1=${(le.stats.t_pass1_ms / 1e3).toFixed(1)}s surf=${(le.stats.t_surface_ms / 1e3).toFixed(1)}s sup=${(le.stats.t_support_ms / 1e3).toFixed(1)}s emit=${(le.stats.t_emit_ms / 1e3).toFixed(1)}s reuse=${Re.reuse_stages}`), p.current[Z] = le, A(), G(Z, le), ve(!1), q(Z), ue(""), P(null), Ae ? $("Memory pressure — finished in economy mode (no preview, G-code can still be downloaded)") : Pe && $("Arachne wall generation failed (degenerate geometry) — finished with classic walls (G-code is fine)");
|
|
1035
|
+
} catch (le) {
|
|
1036
|
+
if (ve(!1), String((le == null ? void 0 : le.message) || le).includes("canceled")) {
|
|
1037
|
+
$("Slice canceled");
|
|
923
1038
|
return;
|
|
924
1039
|
}
|
|
925
|
-
|
|
1040
|
+
P({ scope: "current" }), ue("Slice failed (economy mode failed too): " + le.message);
|
|
926
1041
|
}
|
|
927
1042
|
}
|
|
928
1043
|
}
|
|
929
|
-
async function
|
|
930
|
-
const
|
|
931
|
-
if (
|
|
932
|
-
|
|
1044
|
+
async function se() {
|
|
1045
|
+
const Q = _;
|
|
1046
|
+
if (P(null), !!Q) {
|
|
1047
|
+
R.current = !0;
|
|
933
1048
|
try {
|
|
934
|
-
await
|
|
1049
|
+
await I(Q.scope);
|
|
935
1050
|
} finally {
|
|
936
|
-
|
|
1051
|
+
R.current = !1;
|
|
937
1052
|
}
|
|
938
1053
|
}
|
|
939
1054
|
}
|
|
940
|
-
function
|
|
941
|
-
|
|
1055
|
+
function ye() {
|
|
1056
|
+
ge((Q) => Math.min(tr, Q + 1));
|
|
942
1057
|
}
|
|
943
|
-
function
|
|
944
|
-
|
|
945
|
-
if (
|
|
946
|
-
const
|
|
947
|
-
return delete
|
|
1058
|
+
function xe() {
|
|
1059
|
+
ge((Q) => {
|
|
1060
|
+
if (Q <= 1) return Q;
|
|
1061
|
+
const Z = Q - 1;
|
|
1062
|
+
return delete p.current[Z], w(Z), A(), c.current >= Z && je(Z - 1), Z;
|
|
948
1063
|
});
|
|
949
1064
|
}
|
|
950
|
-
function
|
|
951
|
-
c.current =
|
|
1065
|
+
function je(Q) {
|
|
1066
|
+
c.current = Q, Ee(Q), o.current = 0, J === "preview" && q(Q);
|
|
952
1067
|
}
|
|
953
|
-
return { showPlateResult:
|
|
1068
|
+
return { showPlateResult: q, refreshSlicedCount: A, exportAllGcode: u, onSlice: I, retryDowngrade: se, addPlate: ye, deletePlate: xe, selectPlate: je };
|
|
954
1069
|
}
|
|
955
|
-
function
|
|
1070
|
+
function no(t) {
|
|
956
1071
|
const {
|
|
957
|
-
apiRef:
|
|
1072
|
+
apiRef: r,
|
|
958
1073
|
objectsRef: c,
|
|
959
|
-
layersDataRef:
|
|
960
|
-
segDataRef:
|
|
961
|
-
plateResultsRef:
|
|
962
|
-
plateOffsetsRef:
|
|
963
|
-
clearToolpaths:
|
|
964
|
-
refreshSlicedCount:
|
|
965
|
-
dragOver:
|
|
966
|
-
setError:
|
|
967
|
-
setTriWarn:
|
|
968
|
-
setProgress:
|
|
969
|
-
setStats:
|
|
970
|
-
setOverBed:
|
|
971
|
-
setLayerCount:
|
|
972
|
-
setSegCount:
|
|
973
|
-
setColorRange:
|
|
974
|
-
setSliceNotice:
|
|
975
|
-
setDowngradeOffer:
|
|
976
|
-
setGcodeUrl:
|
|
977
|
-
setCanvasMode:
|
|
978
|
-
setObjects:
|
|
979
|
-
setDragOver:
|
|
980
|
-
} =
|
|
981
|
-
async function
|
|
982
|
-
var
|
|
983
|
-
const
|
|
984
|
-
if (!
|
|
985
|
-
|
|
1074
|
+
layersDataRef: i,
|
|
1075
|
+
segDataRef: o,
|
|
1076
|
+
plateResultsRef: p,
|
|
1077
|
+
plateOffsetsRef: h,
|
|
1078
|
+
clearToolpaths: j,
|
|
1079
|
+
refreshSlicedCount: x,
|
|
1080
|
+
dragOver: B,
|
|
1081
|
+
setError: z,
|
|
1082
|
+
setTriWarn: m,
|
|
1083
|
+
setProgress: L,
|
|
1084
|
+
setStats: D,
|
|
1085
|
+
setOverBed: R,
|
|
1086
|
+
setLayerCount: K,
|
|
1087
|
+
setSegCount: J,
|
|
1088
|
+
setColorRange: _,
|
|
1089
|
+
setSliceNotice: T,
|
|
1090
|
+
setDowngradeOffer: F,
|
|
1091
|
+
setGcodeUrl: ce,
|
|
1092
|
+
setCanvasMode: pe,
|
|
1093
|
+
setObjects: w,
|
|
1094
|
+
setDragOver: S
|
|
1095
|
+
} = t;
|
|
1096
|
+
async function E(f) {
|
|
1097
|
+
var oe, ue;
|
|
1098
|
+
const N = Array.from(f || []).filter(($) => an.includes(ma($.name))), O = Array.from(f || []).length - N.length;
|
|
1099
|
+
if (!N.length) {
|
|
1100
|
+
O && z("Supported formats: STL/OBJ/3MF/AMF/PLY");
|
|
986
1101
|
return;
|
|
987
1102
|
}
|
|
988
|
-
|
|
989
|
-
let
|
|
990
|
-
for (const
|
|
1103
|
+
z(""), m(""), L(0), i.current = null, o.current = null, p.current = {}, h.current = {}, j(), x(), D(null), R(!1), K(0), J(0), _(null), T(""), F(null), ce(($) => ($ && URL.revokeObjectURL($), "")), pe("prepare"), (oe = r.current) == null || oe.showObjects();
|
|
1104
|
+
let H = 0;
|
|
1105
|
+
for (const $ of N)
|
|
991
1106
|
try {
|
|
992
|
-
const
|
|
993
|
-
for (const
|
|
994
|
-
(
|
|
995
|
-
console.info(`[vp-prof] load ${
|
|
996
|
-
} catch (
|
|
997
|
-
|
|
1107
|
+
const P = performance.now(), ve = await $.arrayBuffer(), Me = performance.now(), ge = await fa($.name, ve), Ee = performance.now();
|
|
1108
|
+
for (const b of ge)
|
|
1109
|
+
(ue = r.current) == null || ue.addObject(b.name, b.modelPos), H += b.modelPos.length / 9;
|
|
1110
|
+
console.info(`[vp-prof] load ${$.name}: read ${(Me - P).toFixed(0)}ms, parse ${(Ee - Me).toFixed(0)}ms, scene ${(performance.now() - Ee).toFixed(0)}ms`);
|
|
1111
|
+
} catch (P) {
|
|
1112
|
+
z(`Failed to load ${$.name}: ${P && P.message || P}`);
|
|
998
1113
|
}
|
|
999
|
-
|
|
1114
|
+
w(c.current.map(($) => ({ id: $.id, name: $.name, extruder: $.extruder, visible: $.visible !== !1 }))), H > 1e5 && m(`${Math.round(H).toLocaleString()} triangles — slicing may take a while`);
|
|
1000
1115
|
}
|
|
1001
|
-
function
|
|
1002
|
-
|
|
1116
|
+
function M(f) {
|
|
1117
|
+
E(f.target.files), f.target.value = "";
|
|
1003
1118
|
}
|
|
1004
|
-
function f
|
|
1005
|
-
var
|
|
1006
|
-
(
|
|
1119
|
+
function y(f) {
|
|
1120
|
+
var N;
|
|
1121
|
+
(N = r.current) == null || N.removeObject(f), w(c.current.map((O) => ({ id: O.id, name: O.name, extruder: O.extruder, visible: O.visible !== !1 })));
|
|
1007
1122
|
}
|
|
1008
|
-
function
|
|
1009
|
-
var
|
|
1010
|
-
|
|
1123
|
+
function v(f) {
|
|
1124
|
+
var N;
|
|
1125
|
+
f.preventDefault(), S(!1), E((N = f.dataTransfer) == null ? void 0 : N.files);
|
|
1011
1126
|
}
|
|
1012
|
-
function
|
|
1013
|
-
|
|
1127
|
+
function C(f) {
|
|
1128
|
+
f.preventDefault(), f.dataTransfer && (f.dataTransfer.dropEffect = "copy"), B || S(!0);
|
|
1014
1129
|
}
|
|
1015
|
-
function
|
|
1016
|
-
|
|
1130
|
+
function V(f) {
|
|
1131
|
+
f.currentTarget.contains(f.relatedTarget) || S(!1);
|
|
1017
1132
|
}
|
|
1018
|
-
return { loadFiles:
|
|
1133
|
+
return { loadFiles: E, onFiles: M, removeObject: y, onDrop: v, onDragOver: C, onDragLeave: V };
|
|
1134
|
+
}
|
|
1135
|
+
const on = 0, kt = 1, Bt = 2, $t = 16;
|
|
1136
|
+
function ro(t, r) {
|
|
1137
|
+
return t === "enforcer" ? kt : t === "blocker" ? Bt : t !== "material" || !Number.isInteger(r) || r < 0 ? on : Math.min(r + 1, $t);
|
|
1019
1138
|
}
|
|
1020
|
-
function
|
|
1139
|
+
function ao(t) {
|
|
1021
1140
|
const {
|
|
1022
|
-
three:
|
|
1141
|
+
three: r,
|
|
1023
1142
|
objectsRef: c,
|
|
1024
|
-
apiRef:
|
|
1025
|
-
getWorker:
|
|
1026
|
-
selectedPlateRef:
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
const
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1143
|
+
apiRef: i,
|
|
1144
|
+
getWorker: o,
|
|
1145
|
+
selectedPlateRef: p,
|
|
1146
|
+
selectorGeomRef: h,
|
|
1147
|
+
paintXformRef: j,
|
|
1148
|
+
paintOverlayRef: x,
|
|
1149
|
+
paintModeRef: B,
|
|
1150
|
+
materialExtruderRef: z,
|
|
1151
|
+
extruderColorsRef: m,
|
|
1152
|
+
setError: L,
|
|
1153
|
+
setPaintModeState: D,
|
|
1154
|
+
setPaintCounts: R,
|
|
1155
|
+
setPaintStateCounts: K,
|
|
1156
|
+
setSliceNotice: J
|
|
1157
|
+
} = t, _ = (f) => {
|
|
1158
|
+
const N = new Uint8Array(f);
|
|
1159
|
+
let O = N.length;
|
|
1160
|
+
const H = Math.max(1, Math.floor(N.length / 4096));
|
|
1161
|
+
for (let oe = 0; oe < N.length; oe += H) O = O * 31 + N[oe] | 0;
|
|
1162
|
+
return `${N.length}:${O}`;
|
|
1163
|
+
}, T = (f) => f.__paintLastCounts ?? (f.__paintLastCounts = {});
|
|
1164
|
+
function F() {
|
|
1165
|
+
const f = Array.isArray(m == null ? void 0 : m.current) ? m.current.length : 0, N = [];
|
|
1166
|
+
for (let O = 0; O < Math.min(f, $t); O++)
|
|
1167
|
+
N.push(O + 1);
|
|
1168
|
+
return N.includes(kt) || N.push(kt), N.includes(Bt) || N.push(Bt), N.sort((O, H) => O - H);
|
|
1169
|
+
}
|
|
1170
|
+
function ce() {
|
|
1171
|
+
const f = o();
|
|
1172
|
+
if (!f || f.__paintStateStamped) return f;
|
|
1173
|
+
const N = f.postMessage.bind(f);
|
|
1174
|
+
return f.postMessage = (...O) => {
|
|
1175
|
+
const H = O[0];
|
|
1176
|
+
if (H && H.cmd === "overlay" && !H.states)
|
|
1177
|
+
return O[0] = { ...H, states: F() }, N(...O);
|
|
1178
|
+
if (H && H.cmd === "paint") {
|
|
1179
|
+
const oe = ro(B.current, z == null ? void 0 : z.current);
|
|
1180
|
+
if (oe === on) {
|
|
1181
|
+
const ue = { ...H, cmd: "erase", states: F() };
|
|
1182
|
+
delete ue.enforcer, O[0] = ue;
|
|
1183
|
+
} else
|
|
1184
|
+
O[0] = { ...H, state: oe, states: F(), enforcer: oe === kt };
|
|
1047
1185
|
}
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
const
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1186
|
+
return N(...O);
|
|
1187
|
+
}, f.addEventListener("message", (O) => {
|
|
1188
|
+
const H = O.data;
|
|
1189
|
+
if (!H || H.type !== "painted" || !H.counts) return;
|
|
1190
|
+
K == null || K(H.counts);
|
|
1191
|
+
const oe = T(f), ue = Object.entries(H.counts).filter(([$, P]) => oe[$] !== P).map(([$]) => Number($));
|
|
1192
|
+
for (const [$, P] of Object.entries(H.counts)) oe[$] = P;
|
|
1193
|
+
ue.length && N({ cmd: "overlay", states: ue });
|
|
1194
|
+
}), f.__paintStateStamped = !0, f;
|
|
1054
1195
|
}
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1196
|
+
const pe = { 1: "#2b6cff", 2: "#e23b3b" };
|
|
1197
|
+
function w(f) {
|
|
1198
|
+
var N;
|
|
1199
|
+
return B.current === "material" ? ((N = m == null ? void 0 : m.current) == null ? void 0 : N[f - 1]) ?? "#9aa4b2" : pe[f] ?? "#9aa4b2";
|
|
1059
1200
|
}
|
|
1060
|
-
function
|
|
1061
|
-
var
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1201
|
+
function S(f) {
|
|
1202
|
+
var oe;
|
|
1203
|
+
const N = r.current, O = x.current, H = (oe = O == null ? void 0 : O.get) == null ? void 0 : oe.call(O, f);
|
|
1204
|
+
H && (N.objectsGroup && N.objectsGroup.remove(H), H.geometry.dispose(), H.material.dispose(), O.delete(f));
|
|
1205
|
+
}
|
|
1206
|
+
function E() {
|
|
1207
|
+
const f = x.current;
|
|
1208
|
+
if (f != null && f.keys)
|
|
1209
|
+
for (const N of [...f.keys()]) S(N);
|
|
1210
|
+
}
|
|
1211
|
+
function M(f, N, O) {
|
|
1212
|
+
var P, ve, Me;
|
|
1213
|
+
const H = r.current;
|
|
1214
|
+
if (!H.objectsGroup) return;
|
|
1215
|
+
const oe = j.current || { cx: 0, cy: 0, minz: 0 };
|
|
1216
|
+
(P = x.current) != null && P.set || (x.current = /* @__PURE__ */ new Map());
|
|
1217
|
+
const ue = (ge, Ee) => {
|
|
1218
|
+
if (!ge || ge.length < 9) return null;
|
|
1219
|
+
const b = new Float32Array(ge.length);
|
|
1220
|
+
for (let q = 0; q < ge.length; q += 3) {
|
|
1221
|
+
const s = ge[q], d = ge[q + 1], A = ge[q + 2];
|
|
1222
|
+
b[q] = s + oe.cx, b[q + 1] = A + oe.minz, b[q + 2] = -(d + oe.cy);
|
|
1223
|
+
}
|
|
1224
|
+
const k = new W.BufferGeometry();
|
|
1225
|
+
k.setAttribute("position", new W.Float32BufferAttribute(b, 3));
|
|
1226
|
+
const G = new W.Mesh(k, new W.MeshBasicMaterial({ color: Ee, transparent: !0, opacity: 0.55, side: W.DoubleSide, depthTest: !1 }));
|
|
1227
|
+
return G.renderOrder = 999, H.objectsGroup.add(G), G;
|
|
1228
|
+
}, $ = O ? Object.keys(O).map(Number).sort((ge, Ee) => ge - Ee).map((ge) => [ge, O[ge]]) : [[kt, f], [Bt, N]];
|
|
1229
|
+
for (const [ge, Ee] of $) {
|
|
1230
|
+
S(ge);
|
|
1231
|
+
const b = ue(Ee, w(ge));
|
|
1232
|
+
b && x.current.set(ge, b);
|
|
1233
|
+
}
|
|
1234
|
+
(Me = (ve = r.current).invalidate) == null || Me.call(ve);
|
|
1235
|
+
}
|
|
1236
|
+
function y() {
|
|
1237
|
+
E(), x.current = null;
|
|
1238
|
+
}
|
|
1239
|
+
function v(f = null) {
|
|
1240
|
+
var oe;
|
|
1241
|
+
const N = f ?? ((oe = i.current) == null ? void 0 : oe.buildMergedSTL(p.current));
|
|
1242
|
+
if (!N) return;
|
|
1243
|
+
j.current = { cx: N.offX, cy: -N.offZ, minz: 0 };
|
|
1244
|
+
const O = h.current, H = _(N.buf);
|
|
1245
|
+
if ((O == null ? void 0 : O.identity) !== H) {
|
|
1246
|
+
const ue = T(o()), $ = Object.values(ue).some((Me) => Me > 0), P = O != null && O.topology === N.topology, ve = ce();
|
|
1247
|
+
if (ve.postMessage({ cmd: "prepare", stl: N.buf, keepPaint: P }), h.current = { identity: H, topology: N.topology }, P)
|
|
1248
|
+
$ && ve.postMessage({ cmd: "overlay" });
|
|
1249
|
+
else {
|
|
1250
|
+
K == null || K({}), R == null || R({ enf: 0, blk: 0 }), y();
|
|
1251
|
+
for (const Me of Object.keys(ue)) delete ue[Me];
|
|
1252
|
+
$ && (J == null || J("The model changed, so the painted regions were reset — the paint is tied to the facets it was brushed onto."));
|
|
1253
|
+
}
|
|
1065
1254
|
}
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1255
|
+
}
|
|
1256
|
+
function C(f) {
|
|
1257
|
+
var N, O;
|
|
1258
|
+
if (f !== "off" && c.current.length === 0) {
|
|
1259
|
+
L("Upload an STL first");
|
|
1260
|
+
return;
|
|
1070
1261
|
}
|
|
1071
|
-
|
|
1262
|
+
f !== "off" && ((N = i.current) == null || N.detachTransform(), v()), B.current = f, D(f), (O = i.current) == null || O.refreshCursor();
|
|
1072
1263
|
}
|
|
1073
|
-
function
|
|
1074
|
-
|
|
1264
|
+
function V() {
|
|
1265
|
+
o().postMessage({ cmd: "clear" }), y(), R({ enf: 0, blk: 0 }), K == null || K({});
|
|
1075
1266
|
}
|
|
1076
|
-
return { rebuildPaintOverlay:
|
|
1267
|
+
return { rebuildPaintOverlay: M, clearPaintOverlay: y, setPaintMode: C, clearPaint: V, registerSelector: v };
|
|
1077
1268
|
}
|
|
1078
|
-
function
|
|
1269
|
+
function oo(t) {
|
|
1079
1270
|
const {
|
|
1080
|
-
apiRef:
|
|
1271
|
+
apiRef: r,
|
|
1081
1272
|
objectsRef: c,
|
|
1082
|
-
clipboardRef:
|
|
1083
|
-
paintModeRef:
|
|
1084
|
-
setPaintMode:
|
|
1085
|
-
removeObject:
|
|
1086
|
-
refreshObjects:
|
|
1087
|
-
setError:
|
|
1088
|
-
setSliceNotice:
|
|
1089
|
-
} =
|
|
1090
|
-
function
|
|
1091
|
-
var
|
|
1092
|
-
const
|
|
1093
|
-
if (!
|
|
1094
|
-
|
|
1273
|
+
clipboardRef: i,
|
|
1274
|
+
paintModeRef: o,
|
|
1275
|
+
setPaintMode: p,
|
|
1276
|
+
removeObject: h,
|
|
1277
|
+
refreshObjects: j,
|
|
1278
|
+
setError: x,
|
|
1279
|
+
setSliceNotice: B
|
|
1280
|
+
} = t;
|
|
1281
|
+
function z() {
|
|
1282
|
+
var F, ce, pe;
|
|
1283
|
+
const _ = (F = r.current) == null ? void 0 : F.selectedObjectId();
|
|
1284
|
+
if (!_) {
|
|
1285
|
+
x("Select an object to duplicate first");
|
|
1095
1286
|
return;
|
|
1096
1287
|
}
|
|
1097
|
-
const
|
|
1098
|
-
|
|
1288
|
+
const T = (ce = r.current) == null ? void 0 : ce.getSnapshot(_);
|
|
1289
|
+
T && ((pe = r.current) == null || pe.spawnSnapshot(T), j(), x(""));
|
|
1099
1290
|
}
|
|
1100
|
-
function
|
|
1101
|
-
var
|
|
1102
|
-
const
|
|
1103
|
-
if (!
|
|
1104
|
-
|
|
1291
|
+
function m() {
|
|
1292
|
+
var T, F;
|
|
1293
|
+
const _ = (T = r.current) == null ? void 0 : T.selectedObjectId();
|
|
1294
|
+
if (!_) {
|
|
1295
|
+
x("Select an object to copy first");
|
|
1105
1296
|
return;
|
|
1106
1297
|
}
|
|
1107
|
-
|
|
1298
|
+
i.current = (F = r.current) == null ? void 0 : F.getSnapshot(_), x(""), B("Object copied (paste with Ctrl+V)");
|
|
1108
1299
|
}
|
|
1109
|
-
function
|
|
1110
|
-
var
|
|
1111
|
-
|
|
1300
|
+
function L() {
|
|
1301
|
+
var _;
|
|
1302
|
+
i.current && ((_ = r.current) == null || _.spawnSnapshot(i.current), j());
|
|
1112
1303
|
}
|
|
1113
|
-
function
|
|
1114
|
-
var
|
|
1115
|
-
const
|
|
1116
|
-
if (!
|
|
1117
|
-
|
|
1304
|
+
function D() {
|
|
1305
|
+
var T;
|
|
1306
|
+
const _ = (T = r.current) == null ? void 0 : T.selectedObjectId();
|
|
1307
|
+
if (!_) {
|
|
1308
|
+
x("Select an object to delete first");
|
|
1118
1309
|
return;
|
|
1119
1310
|
}
|
|
1120
|
-
|
|
1311
|
+
h(_), x("");
|
|
1121
1312
|
}
|
|
1122
|
-
function
|
|
1123
|
-
var
|
|
1124
|
-
const
|
|
1125
|
-
if (
|
|
1126
|
-
for (const
|
|
1127
|
-
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
function
|
|
1131
|
-
var
|
|
1132
|
-
const
|
|
1133
|
-
if (!
|
|
1134
|
-
|
|
1313
|
+
function R() {
|
|
1314
|
+
var T;
|
|
1315
|
+
const _ = c.current.map((F) => F.id);
|
|
1316
|
+
if (_.length) {
|
|
1317
|
+
for (const F of _) (T = r.current) == null || T.removeObject(F);
|
|
1318
|
+
j(), B(`Deleted all ${_.length} object(s)`);
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
function K() {
|
|
1322
|
+
var pe, w;
|
|
1323
|
+
const _ = (pe = r.current) == null ? void 0 : pe.selectedObjectId();
|
|
1324
|
+
if (!_) {
|
|
1325
|
+
x("Select an object to split first");
|
|
1135
1326
|
return;
|
|
1136
1327
|
}
|
|
1137
|
-
const
|
|
1138
|
-
if (!
|
|
1139
|
-
let
|
|
1328
|
+
const T = (w = r.current) == null ? void 0 : w.getSnapshot(_);
|
|
1329
|
+
if (!T) return;
|
|
1330
|
+
let F;
|
|
1140
1331
|
try {
|
|
1141
|
-
|
|
1142
|
-
} catch (
|
|
1143
|
-
|
|
1332
|
+
F = ha(T.localPos);
|
|
1333
|
+
} catch (S) {
|
|
1334
|
+
x("Split failed: " + ((S == null ? void 0 : S.message) || S));
|
|
1144
1335
|
return;
|
|
1145
1336
|
}
|
|
1146
|
-
if (!
|
|
1147
|
-
|
|
1337
|
+
if (!F || F.length < 2) {
|
|
1338
|
+
x("No separate parts to split — this is a single connected mesh");
|
|
1148
1339
|
return;
|
|
1149
1340
|
}
|
|
1150
|
-
const
|
|
1151
|
-
|
|
1152
|
-
var
|
|
1153
|
-
return (
|
|
1154
|
-
{ name: `${
|
|
1341
|
+
const ce = String(T.name || "object").replace(/\.[^.]+$/, "");
|
|
1342
|
+
h(_), F.forEach((S, E) => {
|
|
1343
|
+
var M;
|
|
1344
|
+
return (M = r.current) == null ? void 0 : M.spawnSnapshot(
|
|
1345
|
+
{ name: `${ce}_${E + 1}`, localPos: S, rot: T.rot, scale: T.scale, pos: T.pos },
|
|
1155
1346
|
!0
|
|
1156
1347
|
);
|
|
1157
|
-
}),
|
|
1348
|
+
}), j(), x(""), B(`Split into ${F.length} objects`);
|
|
1158
1349
|
}
|
|
1159
|
-
function
|
|
1160
|
-
var
|
|
1161
|
-
|
|
1350
|
+
function J(_) {
|
|
1351
|
+
var T;
|
|
1352
|
+
o.current !== "off" && p("off"), (T = r.current) == null || T.setMode(_);
|
|
1162
1353
|
}
|
|
1163
|
-
return { duplicateSelected:
|
|
1354
|
+
return { duplicateSelected: z, copySelected: m, pasteClipboard: L, deleteSelected: D, deleteAllObjects: R, splitSelected: K, setGizmo: J };
|
|
1164
1355
|
}
|
|
1165
|
-
function
|
|
1166
|
-
return /* @__PURE__ */ e.createElement("header", { className: "topbar" }, /* @__PURE__ */ e.createElement("div", { className: "tb-left" }, /* @__PURE__ */ e.createElement("a", { href: "/", className: "tb-logo" }, /* @__PURE__ */ e.createElement("b", null, "Three"), "Slicer ", /* @__PURE__ */ e.createElement("span", { className: "tb-re" }, "RE")), /* @__PURE__ */ e.createElement("button", { className: "tb-btn", onClick:
|
|
1356
|
+
function lo({ showTabs: t, canvasMode: r, onCanvasMode: c, previewEnabled: i, onOpen: o }) {
|
|
1357
|
+
return /* @__PURE__ */ e.createElement("header", { className: "topbar" }, /* @__PURE__ */ e.createElement("div", { className: "tb-left" }, /* @__PURE__ */ e.createElement("a", { href: "/", className: "tb-logo" }, /* @__PURE__ */ e.createElement("b", null, "Three"), "Slicer ", /* @__PURE__ */ e.createElement("span", { className: "tb-re" }, "RE")), /* @__PURE__ */ e.createElement("button", { className: "tb-btn", onClick: o, title: "Open a model file — every existing object is cleared", "data-testid": "open-file" }, /* @__PURE__ */ e.createElement("img", { src: $a, alt: "" }), /* @__PURE__ */ e.createElement("span", null, "Open"))), t && /* @__PURE__ */ e.createElement("div", { className: "tb-tabs", role: "tablist", "aria-label": "Canvas mode" }, /* @__PURE__ */ e.createElement("button", { role: "tab", className: r === "prepare" ? "on" : "", onClick: () => c("prepare"), "data-testid": "mode-prepare", title: "Arrange, transform and paint supports" }, "Prepare"), /* @__PURE__ */ e.createElement("button", { role: "tab", className: r === "preview" ? "on" : "", onClick: () => c("preview"), disabled: !i, "data-testid": "mode-preview", title: "Preview the sliced toolpaths (enabled after slicing)" }, "Preview")), /* @__PURE__ */ e.createElement("div", { className: "tb-right" }, /* @__PURE__ */ e.createElement("button", { className: "tb-icon", disabled: !0, title: "Undo — not implemented (needs an action history stack)" }, "↶"), /* @__PURE__ */ e.createElement("button", { className: "tb-icon", disabled: !0, title: "Redo — not implemented (needs an action history stack)" }, "↷")));
|
|
1167
1358
|
}
|
|
1168
|
-
function
|
|
1169
|
-
const
|
|
1170
|
-
return /* @__PURE__ */ e.createElement("nav", { className: "left-rail", role: "toolbar", "aria-label": "Gizmo tools" }, /* @__PURE__ */ e.createElement("button", { className:
|
|
1359
|
+
function so({ gizmoMode: t, paintMode: r, onGizmo: c, onTogglePaint: i }) {
|
|
1360
|
+
const o = (p) => t === p && r === "off" ? "on" : "";
|
|
1361
|
+
return /* @__PURE__ */ e.createElement("nav", { className: "left-rail", role: "toolbar", "aria-label": "Gizmo tools" }, /* @__PURE__ */ e.createElement("button", { className: o("translate"), onClick: () => c("translate"), title: "Move the object — drag a gizmo axis or use arrow keys for 10mm (Shift 1mm) (M/G)", "data-testid": "gizmo-move" }, /* @__PURE__ */ e.createElement("img", { src: Fa, alt: "Move" })), /* @__PURE__ */ e.createElement("button", { className: o("rotate"), onClick: () => c("rotate"), title: "Rotate the object — PageUp/PageDown rotates in 45° steps (R)", "data-testid": "gizmo-rotate" }, /* @__PURE__ */ e.createElement("img", { src: Va, alt: "Rotate" })), /* @__PURE__ */ e.createElement("button", { className: o("scale"), onClick: () => c("scale"), title: "Scale the object (S)", "data-testid": "gizmo-scale" }, /* @__PURE__ */ e.createElement("img", { src: Ga, alt: "Scale" })), /* @__PURE__ */ e.createElement("div", { className: "rail-sep" }), /* @__PURE__ */ e.createElement("button", { className: r !== "off" ? "on" : "", onClick: i, title: "Brush facets to enforce or block support — the wheel changes the brush size", "data-testid": "gizmo-paint" }, /* @__PURE__ */ e.createElement("img", { src: Za, alt: "Support painting" })));
|
|
1171
1362
|
}
|
|
1172
|
-
function
|
|
1173
|
-
return /* @__PURE__ */ e.createElement("div", { className: "vp-top-toolbar", role: "toolbar", "aria-label": "Object tools" },
|
|
1174
|
-
var
|
|
1175
|
-
return
|
|
1363
|
+
function io({ tools: t }) {
|
|
1364
|
+
return /* @__PURE__ */ e.createElement("div", { className: "vp-top-toolbar", role: "toolbar", "aria-label": "Object tools" }, t.map((r, c) => {
|
|
1365
|
+
var i;
|
|
1366
|
+
return r.sep ? /* @__PURE__ */ e.createElement("span", { key: "sep" + c, className: "vtt-sep" }) : /* @__PURE__ */ e.createElement(
|
|
1176
1367
|
"button",
|
|
1177
1368
|
{
|
|
1178
|
-
key:
|
|
1179
|
-
onClick:
|
|
1180
|
-
disabled: ((
|
|
1181
|
-
title:
|
|
1182
|
-
"data-testid": `tool-${
|
|
1369
|
+
key: r.id,
|
|
1370
|
+
onClick: r.run,
|
|
1371
|
+
disabled: ((i = r.disabled) == null ? void 0 : i.call(r)) ?? !r.run,
|
|
1372
|
+
title: r.tip,
|
|
1373
|
+
"data-testid": `tool-${r.id}`
|
|
1183
1374
|
},
|
|
1184
|
-
/* @__PURE__ */ e.createElement("img", { src:
|
|
1375
|
+
/* @__PURE__ */ e.createElement("img", { src: r.icon, alt: r.label })
|
|
1185
1376
|
);
|
|
1186
1377
|
}));
|
|
1187
1378
|
}
|
|
1188
|
-
function
|
|
1189
|
-
const
|
|
1190
|
-
|
|
1379
|
+
function co({ menu: t, onClose: r, canPaste: c, actions: i }) {
|
|
1380
|
+
const o = (p) => () => {
|
|
1381
|
+
r(), p == null || p();
|
|
1191
1382
|
};
|
|
1192
|
-
return /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement("div", { className: "ctx-scrim", onPointerDown:
|
|
1193
|
-
|
|
1194
|
-
} }), /* @__PURE__ */ e.createElement("div", { className: "ctx-menu", style: { left:
|
|
1383
|
+
return /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement("div", { className: "ctx-scrim", onPointerDown: r, onContextMenu: (p) => {
|
|
1384
|
+
p.preventDefault(), r();
|
|
1385
|
+
} }), /* @__PURE__ */ e.createElement("div", { className: "ctx-menu", style: { left: t.x, top: t.y }, "data-testid": "ctx-menu" }, t.onObject ? /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement("button", { onClick: o(i.duplicate), "data-testid": "ctx-duplicate", title: "Duplicate the selected object at the same scale and rotation, placed beside it" }, "Duplicate ", /* @__PURE__ */ e.createElement("span", { className: "ctx-key" }, "Ctrl+K")), /* @__PURE__ */ e.createElement("button", { onClick: o(i.copy), "data-testid": "ctx-copy", title: "Copy the selected object to the buffer (paste to add it)" }, "Copy ", /* @__PURE__ */ e.createElement("span", { className: "ctx-key" }, "Ctrl+C")), /* @__PURE__ */ e.createElement("button", { onClick: o(i.split), "data-testid": "ctx-split", title: "Split to objects — every disconnected part (connected component) becomes its own object. Split to parts is not implemented (no part concept)" }, "Split"), /* @__PURE__ */ e.createElement("button", { onClick: o(i.placeOnBed), "data-testid": "ctx-seat", title: "Drop every object onto the bed (Z=0)" }, "Place on bed"), /* @__PURE__ */ e.createElement("hr", null), /* @__PURE__ */ e.createElement("button", { className: "danger", onClick: o(i.remove), "data-testid": "ctx-delete", title: "Remove the selected object from the scene" }, "Delete ", /* @__PURE__ */ e.createElement("span", { className: "ctx-key" }, "Del"))) : /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement("button", { onClick: o(i.openFile), "data-testid": "ctx-open", title: "Open a model file and add it to the current plate" }, "Open model…"), /* @__PURE__ */ e.createElement("button", { disabled: !c, onClick: o(i.paste), "data-testid": "ctx-paste", title: "Add the copied object to the current plate" }, "Paste ", /* @__PURE__ */ e.createElement("span", { className: "ctx-key" }, "Ctrl+V")), /* @__PURE__ */ e.createElement("hr", null), /* @__PURE__ */ e.createElement("button", { onClick: o(i.zoomAll), "data-testid": "ctx-zoom-all", title: "Fit the camera so every object is visible" }, "Zoom all ", /* @__PURE__ */ e.createElement("span", { className: "ctx-key" }, "Z")), /* @__PURE__ */ e.createElement("button", { onClick: o(i.zoomBed), "data-testid": "ctx-zoom-bed", title: "Fit the camera to the whole selected plate" }, "Zoom bed ", /* @__PURE__ */ e.createElement("span", { className: "ctx-key" }, "B")))));
|
|
1386
|
+
}
|
|
1387
|
+
function po({ onClose: t }) {
|
|
1388
|
+
return /* @__PURE__ */ e.createElement("div", { className: "help-overlay", "data-testid": "help-overlay", onClick: t }, /* @__PURE__ */ e.createElement("div", { className: "help-card", onClick: (r) => r.stopPropagation() }, /* @__PURE__ */ e.createElement("h3", null, "Shortcuts ", /* @__PURE__ */ e.createElement("span", { className: "muted" }, "(press ? to close)")), /* @__PURE__ */ e.createElement("div", { className: "help-cols" }, /* @__PURE__ */ e.createElement("section", null, /* @__PURE__ */ e.createElement("h4", null, "Prepare"), /* @__PURE__ */ e.createElement("dl", null, /* @__PURE__ */ e.createElement("dt", null, "M / G"), /* @__PURE__ */ e.createElement("dd", null, "Move"), /* @__PURE__ */ e.createElement("dt", null, "R"), /* @__PURE__ */ e.createElement("dd", null, "Rotate"), /* @__PURE__ */ e.createElement("dt", null, "S"), /* @__PURE__ */ e.createElement("dd", null, "Scale"), /* @__PURE__ */ e.createElement("dt", null, "Arrow keys"), /* @__PURE__ */ e.createElement("dd", null, "Move 10mm (Shift 1mm)"), /* @__PURE__ */ e.createElement("dt", null, "PageUp/Down"), /* @__PURE__ */ e.createElement("dd", null, "Rotate 45°"), /* @__PURE__ */ e.createElement("dt", null, "Del"), /* @__PURE__ */ e.createElement("dd", null, "Delete selection"), /* @__PURE__ */ e.createElement("dt", null, "Esc"), /* @__PURE__ */ e.createElement("dd", null, "Clear selection / leave paint"))), /* @__PURE__ */ e.createElement("section", null, /* @__PURE__ */ e.createElement("h4", null, "Preview"), /* @__PURE__ */ e.createElement("dl", null, /* @__PURE__ */ e.createElement("dt", null, "↑ / ↓"), /* @__PURE__ */ e.createElement("dd", null, "Layer (Shift steps of 10)"), /* @__PURE__ */ e.createElement("dt", null, "L"), /* @__PURE__ */ e.createElement("dd", null, "Single layer"), /* @__PURE__ */ e.createElement("dt", null, "T"), /* @__PURE__ */ e.createElement("dd", null, "Travel"), /* @__PURE__ */ e.createElement("dt", null, "Esc"), /* @__PURE__ */ e.createElement("dd", null, "Back to Prepare"))), /* @__PURE__ */ e.createElement("section", null, /* @__PURE__ */ e.createElement("h4", null, "Common"), /* @__PURE__ */ e.createElement("dl", null, /* @__PURE__ */ e.createElement("dt", null, "Ctrl+R"), /* @__PURE__ */ e.createElement("dd", null, "Slice"), /* @__PURE__ */ e.createElement("dt", null, "Ctrl+K / ⌘D"), /* @__PURE__ */ e.createElement("dd", null, "Duplicate"), /* @__PURE__ */ e.createElement("dt", null, "Ctrl+C/V/X"), /* @__PURE__ */ e.createElement("dd", null, "Copy / paste / cut"), /* @__PURE__ */ e.createElement("dt", null, "Z / B"), /* @__PURE__ */ e.createElement("dd", null, "Zoom all / zoom bed"))))));
|
|
1389
|
+
}
|
|
1390
|
+
function uo(t) {
|
|
1391
|
+
const r = String(t ?? "").trim().replace(/^#/, "");
|
|
1392
|
+
if (r.length !== 3 && r.length !== 6) return "#ffffff";
|
|
1393
|
+
const c = r.length === 3 ? r.split("").map((x) => x + x).join("") : r, i = [0, 2, 4].map((x) => parseInt(c.slice(x, x + 2), 16) / 255);
|
|
1394
|
+
if (i.some(Number.isNaN)) return "#ffffff";
|
|
1395
|
+
const [o, p, h] = i;
|
|
1396
|
+
return 0.2126 * o + 0.7152 * p + 0.0722 * h > 0.55 ? "#10141a" : "#ffffff";
|
|
1195
1397
|
}
|
|
1196
|
-
function
|
|
1197
|
-
|
|
1398
|
+
function Dt(t, r) {
|
|
1399
|
+
if (!t) return 0;
|
|
1400
|
+
const c = (Array.isArray(t), t[r]);
|
|
1401
|
+
return Number.isFinite(c) ? c : 0;
|
|
1198
1402
|
}
|
|
1199
|
-
|
|
1200
|
-
|
|
1403
|
+
const mo = [
|
|
1404
|
+
["brush", "brush", "Drag a radius cursor over the model"],
|
|
1405
|
+
["smart", "smart", "Click once to flood the smooth feature under the cursor (Smart fill)"],
|
|
1406
|
+
["bucket", "bucket", "Click once to flood everything sharing the clicked spot's current mark"],
|
|
1407
|
+
["triangle", "triangle", "Click to mark exactly one facet"]
|
|
1408
|
+
], It = (t) => t === "smart" || t === "bucket" || t === "triangle";
|
|
1409
|
+
function ar({ tool: t = "brush", onTool: r, cursor: c = "sphere", onCursor: i, fillAngle: o = 30, onFillAngle: p }) {
|
|
1410
|
+
return /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement("div", { className: "bp-modes bp-tools" }, mo.map(([h, j, x]) => /* @__PURE__ */ e.createElement(
|
|
1411
|
+
"button",
|
|
1412
|
+
{
|
|
1413
|
+
key: h,
|
|
1414
|
+
className: t === h ? "bp-tool on" : "bp-tool",
|
|
1415
|
+
onClick: () => r == null ? void 0 : r(h),
|
|
1416
|
+
title: x,
|
|
1417
|
+
"data-testid": `paint-tool-${h}`
|
|
1418
|
+
},
|
|
1419
|
+
j
|
|
1420
|
+
))), t === "brush" && /* @__PURE__ */ e.createElement("div", { className: "bp-modes bp-tools" }, /* @__PURE__ */ e.createElement(
|
|
1421
|
+
"button",
|
|
1422
|
+
{
|
|
1423
|
+
className: c === "sphere" ? "bp-tool on" : "bp-tool",
|
|
1424
|
+
onClick: () => i == null ? void 0 : i("sphere"),
|
|
1425
|
+
title: "Sphere — a ball around the hit, so the far side of a thin wall is painted too",
|
|
1426
|
+
"data-testid": "paint-cursor-sphere"
|
|
1427
|
+
},
|
|
1428
|
+
"sphere"
|
|
1429
|
+
), /* @__PURE__ */ e.createElement(
|
|
1430
|
+
"button",
|
|
1431
|
+
{
|
|
1432
|
+
className: c === "circle" ? "bp-tool on" : "bp-tool",
|
|
1433
|
+
onClick: () => i == null ? void 0 : i("circle"),
|
|
1434
|
+
title: "Circle — a disc facing the camera, so only the surface you are looking at",
|
|
1435
|
+
"data-testid": "paint-cursor-circle"
|
|
1436
|
+
},
|
|
1437
|
+
"circle"
|
|
1438
|
+
)), (t === "smart" || t === "bucket") && /* @__PURE__ */ e.createElement("label", { className: "bp-radius" }, "Fill angle ", o, "°", /* @__PURE__ */ e.createElement(
|
|
1439
|
+
"input",
|
|
1440
|
+
{
|
|
1441
|
+
type: "range",
|
|
1442
|
+
min: "1",
|
|
1443
|
+
max: "90",
|
|
1444
|
+
step: "1",
|
|
1445
|
+
value: o,
|
|
1446
|
+
onChange: (h) => p == null ? void 0 : p(parseFloat(h.target.value)),
|
|
1447
|
+
"data-testid": "paint-fill-angle"
|
|
1448
|
+
}
|
|
1449
|
+
)));
|
|
1450
|
+
}
|
|
1451
|
+
function fo({
|
|
1452
|
+
colors: t,
|
|
1453
|
+
activeExtruder: r,
|
|
1454
|
+
onSelectExtruder: c,
|
|
1455
|
+
onClear: i,
|
|
1456
|
+
onClose: o,
|
|
1457
|
+
brushRadius: p,
|
|
1458
|
+
onBrushRadius: h,
|
|
1459
|
+
paintCounts: j,
|
|
1460
|
+
paintTool: x,
|
|
1461
|
+
onPaintTool: B,
|
|
1462
|
+
brushCursor: z,
|
|
1463
|
+
onBrushCursor: m,
|
|
1464
|
+
fillAngle: L,
|
|
1465
|
+
onFillAngle: D
|
|
1466
|
+
}) {
|
|
1467
|
+
const R = Array.isArray(t) ? t : [], K = Number.isFinite(p) ? p : 5, J = r == null;
|
|
1468
|
+
return /* @__PURE__ */ e.createElement("div", { className: "brush-panel", "data-testid": "material-paint-tools" }, /* @__PURE__ */ e.createElement("div", { className: "bp-title" }, "Material painting"), /* @__PURE__ */ e.createElement("div", { className: "bp-modes" }, R.map((_, T) => /* @__PURE__ */ e.createElement(
|
|
1469
|
+
"button",
|
|
1470
|
+
{
|
|
1471
|
+
key: T,
|
|
1472
|
+
className: r === T ? "bp-chip on" : "bp-chip",
|
|
1473
|
+
style: { background: _, color: uo(_) },
|
|
1474
|
+
onClick: () => c == null ? void 0 : c(T),
|
|
1475
|
+
title: T === 0 ? "T1 is the default extruder — painting it takes a region back from another tool (same result as the eraser)" : `Paint the brushed facets to print with T${T + 1}`,
|
|
1476
|
+
"data-testid": `material-chip-${T}`
|
|
1477
|
+
},
|
|
1478
|
+
"T",
|
|
1479
|
+
T + 1
|
|
1480
|
+
)), /* @__PURE__ */ e.createElement(
|
|
1481
|
+
"button",
|
|
1482
|
+
{
|
|
1483
|
+
className: J ? "bp-chip bp-eraser on" : "bp-chip bp-eraser",
|
|
1484
|
+
onClick: () => c == null ? void 0 : c(null),
|
|
1485
|
+
title: "Erase — return the brushed facets to the default extruder",
|
|
1486
|
+
"data-testid": "material-eraser"
|
|
1487
|
+
},
|
|
1488
|
+
"erase"
|
|
1489
|
+
)), /* @__PURE__ */ e.createElement("div", { className: "bp-modes bp-actions" }, /* @__PURE__ */ e.createElement(
|
|
1490
|
+
"button",
|
|
1491
|
+
{
|
|
1492
|
+
onClick: () => i == null ? void 0 : i(),
|
|
1493
|
+
"data-testid": "material-paint-clear",
|
|
1494
|
+
title: "Clear every material-painted region on this object"
|
|
1495
|
+
},
|
|
1496
|
+
"Clear"
|
|
1497
|
+
), /* @__PURE__ */ e.createElement(
|
|
1498
|
+
"button",
|
|
1499
|
+
{
|
|
1500
|
+
onClick: () => o == null ? void 0 : o(),
|
|
1501
|
+
"data-testid": "material-paint-close",
|
|
1502
|
+
title: "Leave painting mode (Esc)"
|
|
1503
|
+
},
|
|
1504
|
+
"Close"
|
|
1505
|
+
)), /* @__PURE__ */ e.createElement(
|
|
1506
|
+
ar,
|
|
1507
|
+
{
|
|
1508
|
+
tool: x,
|
|
1509
|
+
onTool: B,
|
|
1510
|
+
cursor: z,
|
|
1511
|
+
onCursor: m,
|
|
1512
|
+
fillAngle: L,
|
|
1513
|
+
onFillAngle: D
|
|
1514
|
+
}
|
|
1515
|
+
), !It(x) && /* @__PURE__ */ e.createElement("label", { className: "bp-radius" }, "Brush radius ", K, "mm", /* @__PURE__ */ e.createElement(
|
|
1516
|
+
"input",
|
|
1517
|
+
{
|
|
1518
|
+
type: "range",
|
|
1519
|
+
min: "1",
|
|
1520
|
+
max: "15",
|
|
1521
|
+
step: "0.5",
|
|
1522
|
+
value: K,
|
|
1523
|
+
onChange: (_) => h == null ? void 0 : h(parseFloat(_.target.value)),
|
|
1524
|
+
"data-testid": "material-brush-radius"
|
|
1525
|
+
}
|
|
1526
|
+
)), /* @__PURE__ */ e.createElement("div", { className: "muted bp-counts", "data-testid": "material-paint-counts" }, R.map((_, T) => `T${T + 1} ${Dt(j, T)}`).join(" · "), R.length > 0 && " · ", It(x) ? "click the model to fill" : "drag over the model to paint"), /* @__PURE__ */ e.createElement("div", { className: "bp-note", "data-testid": "material-paint-note" }, "Painted regions follow the paint outline per layer; a painted flat face fills that surface's shell."));
|
|
1527
|
+
}
|
|
1528
|
+
function ho({
|
|
1529
|
+
paintMode: t,
|
|
1530
|
+
onPaintMode: r,
|
|
1531
|
+
onClear: c,
|
|
1532
|
+
brushRadius: i,
|
|
1533
|
+
onBrushRadius: o,
|
|
1534
|
+
paintCounts: p,
|
|
1535
|
+
paintTool: h,
|
|
1536
|
+
onPaintTool: j,
|
|
1537
|
+
brushCursor: x,
|
|
1538
|
+
onBrushCursor: B,
|
|
1539
|
+
fillAngle: z,
|
|
1540
|
+
onFillAngle: m
|
|
1541
|
+
}) {
|
|
1542
|
+
return /* @__PURE__ */ e.createElement("div", { className: "brush-panel", "data-testid": "paint-tools" }, /* @__PURE__ */ e.createElement("div", { className: "bp-title" }, "Support painting"), /* @__PURE__ */ e.createElement("div", { className: "bp-modes" }, /* @__PURE__ */ e.createElement("button", { className: t === "enforcer" ? "on enf" : "enf", onClick: () => r("enforcer"), title: "Force support under the painted facets", "data-testid": "paint-enforcer" }, "enforcer"), /* @__PURE__ */ e.createElement("button", { className: t === "blocker" ? "on blk" : "blk", onClick: () => r("blocker"), title: "Block support under the painted facets", "data-testid": "paint-blocker" }, "blocker"), /* @__PURE__ */ e.createElement("button", { onClick: c, "data-testid": "paint-clear", title: "Clear every painted enforcer/blocker area" }, "Clear"), /* @__PURE__ */ e.createElement("button", { onClick: () => r("off"), "data-testid": "paint-off", title: "Leave painting mode (Esc)" }, "Close")), /* @__PURE__ */ e.createElement(
|
|
1543
|
+
ar,
|
|
1544
|
+
{
|
|
1545
|
+
tool: h,
|
|
1546
|
+
onTool: j,
|
|
1547
|
+
cursor: x,
|
|
1548
|
+
onCursor: B,
|
|
1549
|
+
fillAngle: z,
|
|
1550
|
+
onFillAngle: m
|
|
1551
|
+
}
|
|
1552
|
+
), !It(h) && /* @__PURE__ */ e.createElement("label", { className: "bp-radius" }, "Brush radius ", i, "mm", /* @__PURE__ */ e.createElement(
|
|
1201
1553
|
"input",
|
|
1202
1554
|
{
|
|
1203
1555
|
type: "range",
|
|
1204
1556
|
min: "1",
|
|
1205
1557
|
max: "15",
|
|
1206
1558
|
step: "0.5",
|
|
1207
|
-
value:
|
|
1208
|
-
onChange: (
|
|
1559
|
+
value: i,
|
|
1560
|
+
onChange: (L) => o(parseFloat(L.target.value)),
|
|
1209
1561
|
"data-testid": "brush-radius"
|
|
1210
1562
|
}
|
|
1211
|
-
)), /* @__PURE__ */ e.createElement("div", { className: "muted bp-counts", "data-testid": "paint-counts" }, "enforcer ",
|
|
1563
|
+
)), /* @__PURE__ */ e.createElement("div", { className: "muted bp-counts", "data-testid": "paint-counts" }, "enforcer ", p.enf, " · blocker ", p.blk, " · ", It(h) ? "click the model to fill" : "drag over the model to paint"));
|
|
1212
1564
|
}
|
|
1213
|
-
function
|
|
1214
|
-
return /* @__PURE__ */ e.createElement("div", { className: "plate-bar", "data-testid": "plate-bar", role: "tablist", "aria-label": "Plates" }, Array.from({ length:
|
|
1565
|
+
function bo({ plateCount: t, selectedPlate: r, maxPlates: c, onSelect: i, onAdd: o, onDelete: p }) {
|
|
1566
|
+
return /* @__PURE__ */ e.createElement("div", { className: "plate-bar", "data-testid": "plate-bar", role: "tablist", "aria-label": "Plates" }, Array.from({ length: t }, (h, j) => /* @__PURE__ */ e.createElement("button", { key: j, role: "tab", className: "plate-tab" + (j === r ? " on" : ""), onClick: () => i(j), title: `Select plate ${j + 1} — in Preview this switches to that plate's result`, "data-testid": `plate-${j}` }, j + 1)), /* @__PURE__ */ e.createElement("button", { className: "plate-add", onClick: o, disabled: t >= c, title: "Add an empty plate (max 9) — each plate slices and exports separately", "data-testid": "plate-add" }, "+"), t > 1 && /* @__PURE__ */ e.createElement("button", { className: "plate-del", onClick: p, title: "Delete the last plate and its slice result", "data-testid": "plate-del" }, "−"));
|
|
1215
1567
|
}
|
|
1216
|
-
const
|
|
1217
|
-
function
|
|
1218
|
-
viewType:
|
|
1219
|
-
onViewType:
|
|
1568
|
+
const rn = (t) => `rgb(${Math.round(t[0] * 255)},${Math.round(t[1] * 255)},${Math.round(t[2] * 255)})`;
|
|
1569
|
+
function go({
|
|
1570
|
+
viewType: t,
|
|
1571
|
+
onViewType: r,
|
|
1220
1572
|
layerCount: c,
|
|
1221
|
-
layerLo:
|
|
1222
|
-
layerHi:
|
|
1223
|
-
segCount:
|
|
1224
|
-
singleLayer:
|
|
1225
|
-
onLayerLo:
|
|
1226
|
-
onLayerHi:
|
|
1227
|
-
onToggleSingle:
|
|
1228
|
-
showTravel:
|
|
1229
|
-
onToggleTravel:
|
|
1230
|
-
colorRange:
|
|
1231
|
-
roleLegend:
|
|
1573
|
+
layerLo: i,
|
|
1574
|
+
layerHi: o,
|
|
1575
|
+
segCount: p,
|
|
1576
|
+
singleLayer: h,
|
|
1577
|
+
onLayerLo: j,
|
|
1578
|
+
onLayerHi: x,
|
|
1579
|
+
onToggleSingle: B,
|
|
1580
|
+
showTravel: z,
|
|
1581
|
+
onToggleTravel: m,
|
|
1582
|
+
colorRange: L,
|
|
1583
|
+
roleLegend: D,
|
|
1584
|
+
extruderColors: R
|
|
1232
1585
|
}) {
|
|
1233
|
-
|
|
1586
|
+
const K = t === "filament", J = Math.max(1, Array.isArray(R) ? R.length : 0);
|
|
1587
|
+
return /* @__PURE__ */ e.createElement("div", { className: "slice-layer", "data-testid": "preview-controls" }, /* @__PURE__ */ e.createElement("label", { className: "view-type-row" }, "View type", /* @__PURE__ */ e.createElement("select", { value: t, onChange: r, "data-testid": "view-type-select", title: "What the toolpath colors represent — feature type, speed, layer height, width, fan, temperature, printing filament" }, Ea.map((_) => /* @__PURE__ */ e.createElement("option", { key: _.key, value: _.key }, _.label)))), /* @__PURE__ */ e.createElement("label", null, "Layer ", /* @__PURE__ */ e.createElement("b", { "data-testid": "layer-range" }, h ? o + 1 : `${i + 1}..${o + 1}`), " / ", c, /* @__PURE__ */ e.createElement("span", { className: "muted" }, " (", p.toLocaleString(), " segments)")), /* @__PURE__ */ e.createElement("div", { className: "dual-slider" }, /* @__PURE__ */ e.createElement("input", { type: "range", min: "0", max: Math.max(0, c - 1), value: i, onChange: j, "data-testid": "layer-lo", title: "Lowest layer to show (also adjustable with ↓/↑)" }), /* @__PURE__ */ e.createElement("input", { type: "range", min: "0", max: Math.max(0, c - 1), value: o, onChange: x, "data-testid": "layer-hi", title: "Highest layer to show (↓/↑, hold Shift for steps of 10)" })), /* @__PURE__ */ e.createElement("div", { className: "layer-ctl" }, /* @__PURE__ */ e.createElement("button", { className: h ? "on" : "", onClick: B, "data-testid": "single-layer-btn", title: "Show only the selected layer (L)" }, "Single layer"), /* @__PURE__ */ e.createElement("label", { className: "slice-travel" }, /* @__PURE__ */ e.createElement("input", { type: "checkbox", checked: z, onChange: m, "data-testid": "travel-toggle", title: "Show non-extruding moves as gray lines (T)" }), " Travel")), K ? (
|
|
1588
|
+
// Swatches only, no share percentage: buildSegmentData accumulates extruded length per feature type
|
|
1589
|
+
// (typeLengths) and never per tool, so a "% per extruder" here would be made up. The millimetres per tool
|
|
1590
|
+
// are the stats card's job. The colors come from TOOL_COLOR because that is exactly what computeColors
|
|
1591
|
+
// paints the segments with — an extruderColors swatch would show the user's picker color, not the toolpath.
|
|
1592
|
+
/* @__PURE__ */ e.createElement("div", { className: "role-legend", "data-testid": "view-legend" }, Array.from({ length: J }, (_, T) => /* @__PURE__ */ e.createElement("span", { key: T, className: "role-item" }, /* @__PURE__ */ e.createElement("i", { style: { background: rn(Hn[T % Hn.length]) } }), "T", T + 1)))
|
|
1593
|
+
) : L && L.cont ? /* @__PURE__ */ e.createElement("div", { className: "grad-legend", "data-testid": "view-legend" }, /* @__PURE__ */ e.createElement("div", { className: "grad-title" }, L.label, " ", /* @__PURE__ */ e.createElement("span", { className: "muted" }, L.unit)), /* @__PURE__ */ e.createElement("div", { className: "grad-bar", "data-testid": "gradient-bar", style: { background: `linear-gradient(to right, ${ka.map(rn).join(",")})` } }), /* @__PURE__ */ e.createElement("div", { className: "grad-minmax" }, /* @__PURE__ */ e.createElement("span", { "data-testid": "grad-min" }, L.min.toFixed(L.unit === "mm" ? 2 : 0)), /* @__PURE__ */ e.createElement("span", { "data-testid": "grad-max" }, L.max.toFixed(L.unit === "mm" ? 2 : 0)))) : /* @__PURE__ */ e.createElement("div", { className: "role-legend", "data-testid": "view-legend" }, D.map((_) => /* @__PURE__ */ e.createElement("span", { key: _.type, className: "role-item" }, /* @__PURE__ */ e.createElement("i", { style: { background: rn(_.color) } }), _.label, " ", /* @__PURE__ */ e.createElement("b", null, _.pct.toFixed(0), "%")))));
|
|
1234
1594
|
}
|
|
1235
|
-
const
|
|
1236
|
-
const
|
|
1237
|
-
return `${Math.floor(
|
|
1238
|
-
},
|
|
1239
|
-
function
|
|
1240
|
-
|
|
1595
|
+
const yo = (t) => {
|
|
1596
|
+
const r = Math.round(t);
|
|
1597
|
+
return `${Math.floor(r / 3600)}h ${String(Math.floor(r % 3600 / 60)).padStart(2, "0")}m ${String(r % 60).padStart(2, "0")}s`;
|
|
1598
|
+
}, xo = { full: "GCodeProcessor", transcribed: "transcribed planner", fallback: "fallback" };
|
|
1599
|
+
function qn(t, r, c) {
|
|
1600
|
+
const i = ((t == null ? void 0 : t[c]) ?? "").trim(), o = ((r == null ? void 0 : r[c]) ?? "").trim();
|
|
1601
|
+
return i || (o ? o.replace(/\s*@.*$/, "") : "");
|
|
1602
|
+
}
|
|
1603
|
+
function vo({ stats: t, overBed: r, extruderColors: c, filamentTypes: i, filamentIds: o }) {
|
|
1604
|
+
if (!t) return null;
|
|
1605
|
+
const p = Array.isArray(t.filamentPerTool) ? t.filamentPerTool : null, j = (p ? p.filter((L) => Number.isFinite(L) && L > 0).length : 0) > 1, x = Number.isFinite(t.filamentPurge) ? t.filamentPurge : 0, B = Array.isArray(t.filamentPurgePerTool) ? t.filamentPurgePerTool : null, z = (L) => Number.isFinite(B == null ? void 0 : B[L]) ? B[L] : 0, m = Array.isArray(c) ? c : [];
|
|
1606
|
+
return /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement("div", null, /* @__PURE__ */ e.createElement("b", null, t.layers), " layers · ", /* @__PURE__ */ e.createElement("b", null, t.segments), " segments"), /* @__PURE__ */ e.createElement("div", null, "Filament ", /* @__PURE__ */ e.createElement("b", null, t.filament.toFixed(1)), " mm"), j && p.map((L, D) => Number.isFinite(L) && L > 0 ? /* @__PURE__ */ e.createElement("div", { className: "stat-tool", key: D, "data-testid": `filament-tool-${D}` }, /* @__PURE__ */ e.createElement("span", { className: "stat-swatch", style: { background: m[D] ?? "#8a9099" } }), "T", D + 1, qn(i, o, D) && /* @__PURE__ */ e.createElement("span", { className: "stat-type", "data-testid": `filament-type-${D}` }, qn(i, o, D)), " ", /* @__PURE__ */ e.createElement("b", null, L.toFixed(1)), " mm", B && z(D) > 0 && /* @__PURE__ */ e.createElement("span", { className: "stat-split", "data-testid": `filament-tool-split-${D}` }, " ", "(model ", (L - z(D)).toFixed(1), " · tower ", z(D).toFixed(1), ")")) : null), j && x > 0 && /* @__PURE__ */ e.createElement("div", { className: "stat-tool", "data-testid": "filament-purge" }, /* @__PURE__ */ e.createElement("span", { className: "stat-swatch stat-swatch-purge" }), "Prime tower / purge ", /* @__PURE__ */ e.createElement("b", null, x.toFixed(1)), " mm"), typeof t.timeSec == "number" && t.timeSec > 0 && /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement("div", { "data-testid": "print-time" }, "⏱ Estimated print ", /* @__PURE__ */ e.createElement("b", null, yo(t.timeSec))), t.limits && // What the estimator actually ran with, echoed back by the kernel — not re-derived from the settings,
|
|
1241
1607
|
// so an unwired limit shows up as a mismatch here instead of being silently reported as applied.
|
|
1242
1608
|
/* @__PURE__ */ e.createElement(
|
|
1243
1609
|
"div",
|
|
1244
1610
|
{
|
|
1245
1611
|
className: "sc-sub",
|
|
1246
1612
|
"data-testid": "print-time-basis",
|
|
1247
|
-
title: Object.entries(
|
|
1613
|
+
title: Object.entries(t.limits).map(([L, D]) => `${L}: ${D}`).join(`
|
|
1248
1614
|
`)
|
|
1249
1615
|
},
|
|
1250
|
-
|
|
1616
|
+
xo[t.engine] ?? t.engine,
|
|
1251
1617
|
" · ",
|
|
1252
|
-
|
|
1618
|
+
t.limits.max_speed_xy,
|
|
1253
1619
|
" mm/s · ",
|
|
1254
|
-
|
|
1620
|
+
t.limits.accel_print,
|
|
1255
1621
|
" mm/s² · jerk ",
|
|
1256
|
-
|
|
1257
|
-
)),
|
|
1622
|
+
t.limits.jerk_xy
|
|
1623
|
+
)), r && /* @__PURE__ */ e.createElement("div", { className: "slice-warn", "data-testid": "over-bed" }, "⚠ Model extends beyond the bed"));
|
|
1258
1624
|
}
|
|
1259
|
-
function
|
|
1260
|
-
const
|
|
1261
|
-
const
|
|
1262
|
-
for (const [
|
|
1263
|
-
for (const [
|
|
1264
|
-
const
|
|
1265
|
-
|
|
1625
|
+
function wo({ bedWidth: t, bedDepth: r, nozzleDia: c, onBedSize: i, settings: o, setSettings: p, motionPanel: h }) {
|
|
1626
|
+
const j = _t(() => Object.entries(oa).sort(([w], [S]) => w.localeCompare(S)), []), x = (o == null ? void 0 : o.printer_settings_id) ?? "", B = _t(() => {
|
|
1627
|
+
const w = /* @__PURE__ */ new Map();
|
|
1628
|
+
for (const [S, E] of j)
|
|
1629
|
+
for (const [M, [y, , v]] of Object.entries(E)) {
|
|
1630
|
+
const C = `${S}\0${v}`;
|
|
1631
|
+
w.has(C) || w.set(C, { vendor: S, model: v, variants: [] }), w.get(C).variants.push({ name: M, nozzle: y });
|
|
1266
1632
|
}
|
|
1267
|
-
for (const
|
|
1268
|
-
return
|
|
1269
|
-
}, [
|
|
1270
|
-
const
|
|
1271
|
-
for (const
|
|
1272
|
-
for (const
|
|
1273
|
-
delete
|
|
1274
|
-
const
|
|
1275
|
-
return
|
|
1633
|
+
for (const S of w.values()) S.variants.sort((E, M) => parseFloat(E.nozzle) - parseFloat(M.nozzle));
|
|
1634
|
+
return w;
|
|
1635
|
+
}, [j]), z = [...B.entries()].find(([, w]) => w.variants.some((S) => S.name === x)), m = (z == null ? void 0 : z[1].variants) ?? [], [L, D] = ae(null), R = (w) => p == null ? void 0 : p((S) => {
|
|
1636
|
+
const E = { ...S };
|
|
1637
|
+
for (const y of St) delete E[y];
|
|
1638
|
+
for (const y of (L == null ? void 0 : L.keys) ?? []) delete E[y];
|
|
1639
|
+
delete E.printer_settings_id, delete E.print_settings_id;
|
|
1640
|
+
const M = w ? ca(w) : null;
|
|
1641
|
+
return M ? { ...E, ...M, printer_settings_id: w } : E;
|
|
1276
1642
|
});
|
|
1277
|
-
|
|
1278
|
-
if (!
|
|
1279
|
-
let
|
|
1280
|
-
return
|
|
1281
|
-
if (!
|
|
1282
|
-
|
|
1283
|
-
const
|
|
1284
|
-
|
|
1285
|
-
if (
|
|
1286
|
-
const
|
|
1287
|
-
if (!
|
|
1288
|
-
for (const
|
|
1289
|
-
return { ...
|
|
1643
|
+
Te(() => {
|
|
1644
|
+
if (!x) return;
|
|
1645
|
+
let w = !0;
|
|
1646
|
+
return la().then((S) => {
|
|
1647
|
+
if (!w) return;
|
|
1648
|
+
D(S);
|
|
1649
|
+
const E = sa(x);
|
|
1650
|
+
p == null || p((M) => {
|
|
1651
|
+
if (M.printer_settings_id !== x || M.print_settings_id) return M;
|
|
1652
|
+
const y = E && S.listFor(x).includes(E) ? S.settingsFor(E) : null;
|
|
1653
|
+
if (!y) return M;
|
|
1654
|
+
for (const v of St) delete y[v];
|
|
1655
|
+
return { ...M, ...y, print_settings_id: E };
|
|
1290
1656
|
});
|
|
1291
1657
|
}), () => {
|
|
1292
|
-
|
|
1658
|
+
w = !1;
|
|
1293
1659
|
};
|
|
1294
|
-
}, [
|
|
1295
|
-
const
|
|
1296
|
-
const
|
|
1297
|
-
for (const
|
|
1298
|
-
|
|
1299
|
-
delete
|
|
1300
|
-
const
|
|
1301
|
-
if (!
|
|
1302
|
-
for (const
|
|
1303
|
-
return { ...
|
|
1304
|
-
}),
|
|
1305
|
-
const
|
|
1306
|
-
if (!
|
|
1307
|
-
const
|
|
1308
|
-
var
|
|
1309
|
-
return
|
|
1660
|
+
}, [x]);
|
|
1661
|
+
const K = L && x ? L.listFor(x) : [], J = (w) => p == null ? void 0 : p((S) => {
|
|
1662
|
+
const E = { ...S };
|
|
1663
|
+
for (const y of L.keys)
|
|
1664
|
+
St.includes(y) || delete E[y];
|
|
1665
|
+
delete E.print_settings_id;
|
|
1666
|
+
const M = w ? L.settingsFor(w) : null;
|
|
1667
|
+
if (!M) return E;
|
|
1668
|
+
for (const y of St) delete M[y];
|
|
1669
|
+
return { ...E, ...M, print_settings_id: w };
|
|
1670
|
+
}), _ = (w) => {
|
|
1671
|
+
const S = B.get(w);
|
|
1672
|
+
if (!S) return R("");
|
|
1673
|
+
const E = S.variants.find((M) => {
|
|
1674
|
+
var y;
|
|
1675
|
+
return M.nozzle === ((y = m.find((v) => v.name === x)) == null ? void 0 : y.nozzle);
|
|
1310
1676
|
});
|
|
1311
|
-
|
|
1312
|
-
},
|
|
1313
|
-
|
|
1677
|
+
R((E ?? S.variants[Math.min(1, S.variants.length - 1)]).name);
|
|
1678
|
+
}, T = ia.filter((w) => o && w in o), F = Math.round(t), ce = Math.round(r), pe = (w) => {
|
|
1679
|
+
w.key === "Enter" && w.target.blur();
|
|
1314
1680
|
};
|
|
1315
|
-
return /* @__PURE__ */ e.createElement("section", { className: "side-card" }, /* @__PURE__ */ e.createElement("div", { className: "sc-head" }, "🖨 Printer"),
|
|
1681
|
+
return /* @__PURE__ */ e.createElement("section", { className: "side-card" }, /* @__PURE__ */ e.createElement("div", { className: "sc-head" }, "🖨 Printer"), p && /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement("div", { className: "sc-info" }, /* @__PURE__ */ e.createElement("span", null, "Model"), /* @__PURE__ */ e.createElement(
|
|
1316
1682
|
"select",
|
|
1317
1683
|
{
|
|
1318
1684
|
className: "sc-model",
|
|
1319
|
-
value: (
|
|
1320
|
-
onChange: (
|
|
1685
|
+
value: (z == null ? void 0 : z[0]) ?? "",
|
|
1686
|
+
onChange: (w) => _(w.target.value),
|
|
1321
1687
|
"data-testid": "printer-model",
|
|
1322
1688
|
title: "Loads this printer's profile (motion limits, bed, nozzle) from the upstream vendor data"
|
|
1323
1689
|
},
|
|
1324
1690
|
/* @__PURE__ */ e.createElement("option", { value: "" }, "Custom (defaults)"),
|
|
1325
|
-
|
|
1326
|
-
)),
|
|
1691
|
+
j.map(([w]) => /* @__PURE__ */ e.createElement("optgroup", { key: w, label: w }, [...B.entries()].filter(([, S]) => S.vendor === w).map(([S, E]) => /* @__PURE__ */ e.createElement("option", { key: S, value: S }, E.model))))
|
|
1692
|
+
)), m.length > 1 && /* @__PURE__ */ e.createElement("div", { className: "sc-info" }, /* @__PURE__ */ e.createElement("span", null, "Nozzle"), /* @__PURE__ */ e.createElement("select", { className: "sc-model", value: x, onChange: (w) => R(w.target.value), "data-testid": "printer-nozzle" }, m.map((w) => /* @__PURE__ */ e.createElement("option", { key: w.name, value: w.name }, w.nozzle, " mm")))), K.length > 0 && /* @__PURE__ */ e.createElement("div", { className: "sc-info" }, /* @__PURE__ */ e.createElement("span", null, "Quality"), /* @__PURE__ */ e.createElement(
|
|
1327
1693
|
"select",
|
|
1328
1694
|
{
|
|
1329
1695
|
className: "sc-model",
|
|
1330
|
-
value: (
|
|
1331
|
-
onChange: (
|
|
1696
|
+
value: (o == null ? void 0 : o.print_settings_id) ?? "",
|
|
1697
|
+
onChange: (w) => J(w.target.value),
|
|
1332
1698
|
"data-testid": "process-preset",
|
|
1333
1699
|
title: "Print preset from the vendor profile — the speeds and accelerations the printer is actually driven at"
|
|
1334
1700
|
},
|
|
1335
1701
|
/* @__PURE__ */ e.createElement("option", { value: "" }, "Custom (defaults)"),
|
|
1336
|
-
|
|
1702
|
+
K.map((w) => /* @__PURE__ */ e.createElement("option", { key: w, value: w }, w.replace(/\s*@.*$/, "")))
|
|
1337
1703
|
))), /* @__PURE__ */ e.createElement("div", { className: "sc-info" }, /* @__PURE__ */ e.createElement("span", null, "Bed"), /* @__PURE__ */ e.createElement("span", { className: "sc-bed", title: "Plate size — applied on Enter or blur. Circular/custom shapes come from the printable_area option" }, /* @__PURE__ */ e.createElement(
|
|
1338
1704
|
"input",
|
|
1339
1705
|
{
|
|
1340
1706
|
type: "number",
|
|
1341
1707
|
min: "1",
|
|
1342
|
-
key: `w${
|
|
1343
|
-
defaultValue:
|
|
1344
|
-
onBlur: (
|
|
1345
|
-
onKeyDown:
|
|
1708
|
+
key: `w${F}`,
|
|
1709
|
+
defaultValue: F,
|
|
1710
|
+
onBlur: (w) => i(+w.target.value, r),
|
|
1711
|
+
onKeyDown: pe,
|
|
1346
1712
|
"data-testid": "bed-w-card"
|
|
1347
1713
|
}
|
|
1348
1714
|
), "×", /* @__PURE__ */ e.createElement(
|
|
@@ -1350,610 +1716,1207 @@ function Gr({ bedWidth: n, bedDepth: a, nozzleDia: c, onBedSize: l, settings: r,
|
|
|
1350
1716
|
{
|
|
1351
1717
|
type: "number",
|
|
1352
1718
|
min: "1",
|
|
1353
|
-
key: `d${
|
|
1354
|
-
defaultValue:
|
|
1355
|
-
onBlur: (
|
|
1356
|
-
onKeyDown:
|
|
1719
|
+
key: `d${ce}`,
|
|
1720
|
+
defaultValue: ce,
|
|
1721
|
+
onBlur: (w) => i(t, +w.target.value),
|
|
1722
|
+
onKeyDown: pe,
|
|
1357
1723
|
"data-testid": "bed-d-card"
|
|
1358
1724
|
}
|
|
1359
|
-
), "mm")), /* @__PURE__ */ e.createElement("div", { className: "sc-info" }, /* @__PURE__ */ e.createElement("span", null, "Nozzle Ø"), /* @__PURE__ */ e.createElement("b", null, c, " mm")),
|
|
1725
|
+
), "mm")), /* @__PURE__ */ e.createElement("div", { className: "sc-info" }, /* @__PURE__ */ e.createElement("span", null, "Nozzle Ø"), /* @__PURE__ */ e.createElement("b", null, c, " mm")), h ? /* @__PURE__ */ e.createElement("details", { className: "sc-fold", "data-testid": "motion-fold" }, /* @__PURE__ */ e.createElement("summary", null, /* @__PURE__ */ e.createElement("span", { className: "sc-fold-lbl" }, "Motion"), /* @__PURE__ */ e.createElement("b", { "data-testid": "motion-source" }, T.length ? `Custom (${T.length})` : "Default")), /* @__PURE__ */ e.createElement("div", { className: "sc-fold-body" }, h)) : /* @__PURE__ */ e.createElement("div", { className: "sc-info" }, /* @__PURE__ */ e.createElement("span", null, "Motion"), /* @__PURE__ */ e.createElement(
|
|
1360
1726
|
"b",
|
|
1361
1727
|
{
|
|
1362
1728
|
"data-testid": "motion-source",
|
|
1363
|
-
title:
|
|
1729
|
+
title: T.length ? `Edited: ${T.join(", ")}` : "Machine limits are at their defaults"
|
|
1364
1730
|
},
|
|
1365
|
-
|
|
1731
|
+
T.length ? `Custom (${T.length})` : "Default"
|
|
1366
1732
|
)));
|
|
1367
1733
|
}
|
|
1368
|
-
|
|
1369
|
-
|
|
1734
|
+
const Xn = ["TabFilament::build", "TabFilament::add_filament_overrides_page"].flatMap((t) => pa[t] ?? []).flatMap((t) => t.groups.flatMap((r) => r.options)).filter((t) => !t.startsWith("<")), or = "three-slicer.filaments";
|
|
1735
|
+
function Yn() {
|
|
1736
|
+
try {
|
|
1737
|
+
return JSON.parse(localStorage.getItem(or)) ?? {};
|
|
1738
|
+
} catch {
|
|
1739
|
+
return {};
|
|
1740
|
+
}
|
|
1370
1741
|
}
|
|
1371
|
-
function
|
|
1372
|
-
|
|
1373
|
-
|
|
1742
|
+
function Kn(t) {
|
|
1743
|
+
try {
|
|
1744
|
+
localStorage.setItem(or, JSON.stringify(t));
|
|
1745
|
+
} catch {
|
|
1746
|
+
}
|
|
1747
|
+
return t;
|
|
1748
|
+
}
|
|
1749
|
+
const Et = (t) => Array.isArray(t) ? t[0] : t;
|
|
1750
|
+
function Eo({
|
|
1751
|
+
colors: t,
|
|
1752
|
+
onColor: r,
|
|
1753
|
+
onAdd: c,
|
|
1754
|
+
onRemove: i,
|
|
1755
|
+
settings: o,
|
|
1756
|
+
setSettings: p,
|
|
1757
|
+
filamentPanel: h,
|
|
1758
|
+
paintMode: j,
|
|
1759
|
+
onPaintExtruder: x,
|
|
1760
|
+
paintCounts: B
|
|
1761
|
+
}) {
|
|
1762
|
+
const z = (o == null ? void 0 : o.printer_settings_id) ?? "", [m, L] = ae(null), [D, R] = ae(Yn), [K, J] = ae(null), [_, T] = ae(0), F = t.length;
|
|
1763
|
+
Te(() => {
|
|
1764
|
+
_ >= F && T(F - 1);
|
|
1765
|
+
}, [F, _]);
|
|
1766
|
+
const ce = _t(() => [.../* @__PURE__ */ new Set([...(m == null ? void 0 : m.keys) ?? [], ...Xn])], [m]), pe = _t(() => {
|
|
1767
|
+
const b = o == null ? void 0 : o.filament_settings_id, k = Array.isArray(b) ? b : b ? [b] : [];
|
|
1768
|
+
return Array.from({ length: F }, (G, q) => k[q] ?? "");
|
|
1769
|
+
}, [o == null ? void 0 : o.filament_settings_id, F]), w = pe[_] ?? "", S = (b, k, G) => {
|
|
1770
|
+
var s;
|
|
1771
|
+
if (!G) return null;
|
|
1772
|
+
if (k != null && k[G]) return "Saved";
|
|
1773
|
+
const q = (s = z ? b == null ? void 0 : b.listFor(z) : b == null ? void 0 : b.all()) == null ? void 0 : s.find((d) => d.name === G);
|
|
1774
|
+
return (q == null ? void 0 : q.type) || null;
|
|
1775
|
+
}, E = (b, k, G, q) => {
|
|
1776
|
+
const s = [.../* @__PURE__ */ new Set([...(b == null ? void 0 : b.keys) ?? [], ...Xn])], d = G.map((I) => I ? k[I] ?? (b == null ? void 0 : b.settingsFor(I)) ?? null : null), A = { ...q };
|
|
1777
|
+
for (const I of s) delete A[I];
|
|
1778
|
+
for (const I of s) {
|
|
1779
|
+
const se = d.map((ye) => ye && I in ye ? Et(ye[I]) : null);
|
|
1780
|
+
se.some((ye) => ye != null) && (A[I] = se);
|
|
1781
|
+
}
|
|
1782
|
+
if (G.every((I) => !I))
|
|
1783
|
+
return delete A.filament_settings_id, delete A.filament_type, A;
|
|
1784
|
+
A.filament_settings_id = G;
|
|
1785
|
+
const u = G.map((I) => S(b, k, I));
|
|
1786
|
+
return u.some((I) => I) && (A.filament_type = u.map((I) => I ?? "")), A;
|
|
1787
|
+
}, M = (b, k, G, q = D) => E(m, q, pe.map((s, d) => d === b ? k : s), G), y = () => {
|
|
1788
|
+
F <= 1 || (i == null || i(_), p == null || p((b) => E(m, D, pe.filter((k, G) => G !== _), b)), T((b) => Math.max(0, Math.min(b, F - 2))));
|
|
1789
|
+
}, v = m && w ? D[w] ?? m.settingsFor(w) : null, C = !!m && ce.some((b) => {
|
|
1790
|
+
if (!(b in (o ?? {}))) return !1;
|
|
1791
|
+
const k = Array.isArray(o[b]) ? o[b][_] : Et(o[b]);
|
|
1792
|
+
return JSON.stringify(k ?? null) !== JSON.stringify(Et(v == null ? void 0 : v[b]) ?? null);
|
|
1793
|
+
}), V = () => {
|
|
1794
|
+
var s;
|
|
1795
|
+
const b = (w || "My material").replace(/\s*@.*$/, "") + (D[w] ? "" : " (custom)"), k = (s = window.prompt(`Save T${_ + 1}'s filament settings as:`, b)) == null ? void 0 : s.trim();
|
|
1796
|
+
if (!k) return;
|
|
1797
|
+
const G = {};
|
|
1798
|
+
for (const d of ce) {
|
|
1799
|
+
if (!(d in (o ?? {}))) continue;
|
|
1800
|
+
const A = Array.isArray(o[d]) ? o[d][_] : Et(o[d]);
|
|
1801
|
+
A != null && (G[d] = [A]);
|
|
1802
|
+
}
|
|
1803
|
+
const q = Kn({ ...D, [k]: G });
|
|
1804
|
+
R(q), J("Saved"), p == null || p((d) => M(_, k, d, q));
|
|
1805
|
+
}, f = () => {
|
|
1806
|
+
if (!D[w] || !window.confirm(`Delete the saved material "${w}"?`)) return;
|
|
1807
|
+
const { [w]: b, ...k } = D;
|
|
1808
|
+
R(Kn(k)), J(null), p == null || p((G) => M(_, "", G, k));
|
|
1809
|
+
};
|
|
1810
|
+
Te(() => {
|
|
1811
|
+
let b = !0;
|
|
1812
|
+
return da().then((k) => {
|
|
1813
|
+
b && (L(k), z && (p == null || p((G) => {
|
|
1814
|
+
if (G.printer_settings_id !== z) return G;
|
|
1815
|
+
const q = k.listFor(z), s = Yn(), d = k.recommendedFor(z)[0] ?? q[0], A = G.filament_settings_id, u = Array.isArray(A) ? A : A ? [A] : [], I = (ye) => ye && (ye in s || q.some((xe) => xe.name === ye)), se = Array.from({ length: F }, (ye, xe) => I(u[xe]) ? u[xe] : (d == null ? void 0 : d.name) ?? "");
|
|
1816
|
+
return se.every((ye, xe) => ye === (u[xe] ?? "")) ? G : E(k, s, se, G);
|
|
1817
|
+
})));
|
|
1818
|
+
}), () => {
|
|
1819
|
+
b = !1;
|
|
1820
|
+
};
|
|
1821
|
+
}, [z, F]);
|
|
1822
|
+
const N = _t(() => {
|
|
1823
|
+
const b = /* @__PURE__ */ new Map();
|
|
1824
|
+
if (!m) return { types: [], byType: b };
|
|
1825
|
+
const k = (s, d) => {
|
|
1826
|
+
b.has(s) || b.set(s, []), b.get(s).push(d);
|
|
1827
|
+
};
|
|
1828
|
+
for (const s of Object.keys(D).sort((d, A) => d.localeCompare(A))) k("Saved", { name: s });
|
|
1829
|
+
if (z) for (const s of m.recommendedFor(z)) k("★ Recommended", s);
|
|
1830
|
+
for (const s of z ? m.listFor(z) : m.all()) k(s.type || "Other", s);
|
|
1831
|
+
const G = ["Saved", "★ Recommended"].filter((s) => b.has(s)), q = [...b.keys()].filter((s) => !G.includes(s)).sort((s, d) => s.localeCompare(d));
|
|
1832
|
+
return { types: [...G, ...q], byType: b };
|
|
1833
|
+
}, [m, z, D]);
|
|
1834
|
+
Te(() => {
|
|
1835
|
+
J(null);
|
|
1836
|
+
}, [z, _]);
|
|
1837
|
+
const H = K ?? ((b) => {
|
|
1838
|
+
if (!b || !m) return null;
|
|
1839
|
+
if (D[b]) return "Saved";
|
|
1840
|
+
const k = (z ? m.listFor(z) : m.all()).find((G) => G.name === b);
|
|
1841
|
+
return k ? k.type || "Other" : null;
|
|
1842
|
+
})(w) ?? N.types[0] ?? "", oe = N.byType.get(H) ?? [], ue = (b) => {
|
|
1843
|
+
J(b);
|
|
1844
|
+
const k = N.byType.get(b) ?? [], G = new Set((N.byType.get("★ Recommended") ?? []).map((s) => s.name)), q = k.find((s) => G.has(s.name)) ?? k[0];
|
|
1845
|
+
q && (p == null || p((s) => M(_, q.name, s)));
|
|
1846
|
+
}, $ = (b) => {
|
|
1847
|
+
if (F < 2) return b;
|
|
1848
|
+
const k = { ...b };
|
|
1849
|
+
for (const G of ce) Array.isArray(k[G]) && (k[G] = k[G][_]);
|
|
1850
|
+
return k;
|
|
1851
|
+
}, P = (b) => p == null ? void 0 : p((k) => {
|
|
1852
|
+
const G = $(k), q = typeof b == "function" ? b(G) : b;
|
|
1853
|
+
if (F < 2) return q;
|
|
1854
|
+
const s = { ...k };
|
|
1855
|
+
for (const d of Object.keys(q)) {
|
|
1856
|
+
if (JSON.stringify(q[d]) === JSON.stringify(G[d])) continue;
|
|
1857
|
+
if (!ce.includes(d)) {
|
|
1858
|
+
s[d] = q[d];
|
|
1859
|
+
continue;
|
|
1860
|
+
}
|
|
1861
|
+
const A = Array.isArray(k[d]) ? [...k[d]] : Array.from({ length: F }, () => null);
|
|
1862
|
+
A[_] = Et(q[d]), s[d] = A;
|
|
1863
|
+
}
|
|
1864
|
+
for (const d of Object.keys(G)) {
|
|
1865
|
+
if (d in q || !ce.includes(d)) continue;
|
|
1866
|
+
const A = Array.isArray(k[d]) ? [...k[d]] : Array.from({ length: F }, () => null);
|
|
1867
|
+
A[_] = null, A.every((u) => u == null) ? delete s[d] : s[d] = A;
|
|
1868
|
+
}
|
|
1869
|
+
return s;
|
|
1870
|
+
}), ve = typeof h == "function" ? h($(o ?? {}), P) : h, Me = (b) => b ? b.replace(/\s*@.*$/, "") : "—", ge = j === "material", Ee = (b) => {
|
|
1871
|
+
T(b), x == null || x(b);
|
|
1872
|
+
};
|
|
1873
|
+
return /* @__PURE__ */ e.createElement("section", { className: "side-card", "data-testid": "filament-section" }, /* @__PURE__ */ e.createElement("div", { className: "sc-head" }, "🧵 Filament ", /* @__PURE__ */ e.createElement("span", { className: "sc-count" }, F), /* @__PURE__ */ e.createElement("span", { className: "sc-head-btns" }, /* @__PURE__ */ e.createElement("button", { onClick: c, disabled: F >= 16, title: "Add a filament (extruder) — up to 16, assignable per object or by painting", "data-testid": "filament-add" }, "+"), /* @__PURE__ */ e.createElement("button", { onClick: y, disabled: F <= 1, title: "Remove the selected filament — objects using it move to T1, later tools shift down", "data-testid": "filament-del" }, "−"))), t.map((b, k) => /* @__PURE__ */ e.createElement(
|
|
1874
|
+
"div",
|
|
1875
|
+
{
|
|
1876
|
+
className: `filament-row${k === _ ? " fil-active" : ""}`,
|
|
1877
|
+
key: k,
|
|
1878
|
+
onClick: () => T(k),
|
|
1879
|
+
"data-testid": `filament-row-${k}`,
|
|
1880
|
+
title: pe[k] ? `T${k + 1}: ${pe[k]}` : `T${k + 1}: no material picked`
|
|
1881
|
+
},
|
|
1882
|
+
/* @__PURE__ */ e.createElement(
|
|
1883
|
+
"input",
|
|
1884
|
+
{
|
|
1885
|
+
type: "color",
|
|
1886
|
+
value: b,
|
|
1887
|
+
onClick: (G) => G.stopPropagation(),
|
|
1888
|
+
onChange: (G) => r(k, G.target.value),
|
|
1889
|
+
title: `T${k + 1} filament color`,
|
|
1890
|
+
"data-testid": `filament-color-${k}`
|
|
1891
|
+
}
|
|
1892
|
+
),
|
|
1893
|
+
/* @__PURE__ */ e.createElement("span", { className: "fil-t" }, "T", k + 1),
|
|
1894
|
+
/* @__PURE__ */ e.createElement("span", { className: "fil-mat", "data-testid": `filament-material-${k}` }, Me(pe[k])),
|
|
1895
|
+
k === 0 && /* @__PURE__ */ e.createElement(
|
|
1896
|
+
"span",
|
|
1897
|
+
{
|
|
1898
|
+
className: "fil-badge",
|
|
1899
|
+
"data-testid": "filament-default-badge",
|
|
1900
|
+
title: "Default extruder — everything not painted with another tool prints with this one"
|
|
1901
|
+
},
|
|
1902
|
+
"default"
|
|
1903
|
+
),
|
|
1904
|
+
Dt(B, k) > 0 && /* @__PURE__ */ e.createElement(
|
|
1905
|
+
"span",
|
|
1906
|
+
{
|
|
1907
|
+
className: "fil-count",
|
|
1908
|
+
"data-testid": `filament-paint-count-${k}`,
|
|
1909
|
+
title: `${Dt(B, k)} facets painted for T${k + 1}`
|
|
1910
|
+
},
|
|
1911
|
+
Dt(B, k)
|
|
1912
|
+
),
|
|
1913
|
+
x && /* @__PURE__ */ e.createElement(
|
|
1914
|
+
"button",
|
|
1915
|
+
{
|
|
1916
|
+
className: ge && k === _ ? "fil-paint on" : "fil-paint",
|
|
1917
|
+
onClick: (G) => {
|
|
1918
|
+
G.stopPropagation(), Ee(k);
|
|
1919
|
+
},
|
|
1920
|
+
"data-testid": `filament-paint-${k}`,
|
|
1921
|
+
title: `Brush parts of a model to print with T${k + 1}`
|
|
1922
|
+
},
|
|
1923
|
+
"🖌"
|
|
1924
|
+
)
|
|
1925
|
+
)), N.types.length > 0 && /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement("div", { className: "sc-info" }, /* @__PURE__ */ e.createElement("span", null, F > 1 ? `T${_ + 1} material` : "Material"), /* @__PURE__ */ e.createElement(
|
|
1926
|
+
"select",
|
|
1927
|
+
{
|
|
1928
|
+
className: "sc-model",
|
|
1929
|
+
value: H,
|
|
1930
|
+
onChange: (b) => ue(b.target.value),
|
|
1931
|
+
"data-testid": "filament-type",
|
|
1932
|
+
title: "Material type — narrows the presets below to the ones made of it"
|
|
1933
|
+
},
|
|
1934
|
+
N.types.map((b) => /* @__PURE__ */ e.createElement("option", { key: b, value: b }, b, " (", N.byType.get(b).length, ")"))
|
|
1935
|
+
)), /* @__PURE__ */ e.createElement("div", { className: "sc-info" }, /* @__PURE__ */ e.createElement("span", null, "Preset"), /* @__PURE__ */ e.createElement(
|
|
1936
|
+
"select",
|
|
1937
|
+
{
|
|
1938
|
+
className: "sc-model",
|
|
1939
|
+
value: w,
|
|
1940
|
+
onChange: (b) => p == null ? void 0 : p((k) => M(_, b.target.value, k)),
|
|
1941
|
+
"data-testid": "filament-preset",
|
|
1942
|
+
title: "Material preset from the upstream vendor profiles — temperatures, flow ratio, cooling and retraction"
|
|
1943
|
+
},
|
|
1944
|
+
/* @__PURE__ */ e.createElement("option", { value: "" }, "Custom (defaults)"),
|
|
1945
|
+
oe.map((b) => /* @__PURE__ */ e.createElement("option", { key: b.name, value: b.name }, Me(b.name)))
|
|
1946
|
+
)), /* @__PURE__ */ e.createElement("div", { className: "sc-info" }, /* @__PURE__ */ e.createElement("span", { className: "sc-dirty" }, C ? "● Modified" : ""), /* @__PURE__ */ e.createElement("span", { className: "sc-head-btns sc-preset-btns" }, /* @__PURE__ */ e.createElement(
|
|
1947
|
+
"button",
|
|
1948
|
+
{
|
|
1949
|
+
onClick: V,
|
|
1950
|
+
"data-testid": "filament-save",
|
|
1951
|
+
title: "Save this extruder's filament values as your own material — system presets are vendor data and stay read-only"
|
|
1952
|
+
},
|
|
1953
|
+
"Save as…"
|
|
1954
|
+
), /* @__PURE__ */ e.createElement(
|
|
1955
|
+
"button",
|
|
1956
|
+
{
|
|
1957
|
+
onClick: f,
|
|
1958
|
+
disabled: !D[w],
|
|
1959
|
+
"data-testid": "filament-delete",
|
|
1960
|
+
title: "Delete this saved material"
|
|
1961
|
+
},
|
|
1962
|
+
"Delete"
|
|
1963
|
+
)))), ve && N.types.length > 0 && /* @__PURE__ */ e.createElement("details", { className: "sc-fold", "data-testid": "filament-fold" }, /* @__PURE__ */ e.createElement("summary", null, /* @__PURE__ */ e.createElement("span", { className: "sc-fold-lbl" }, "Settings"), /* @__PURE__ */ e.createElement("b", null, C ? "Modified" : "Preset")), /* @__PURE__ */ e.createElement("div", { className: "sc-fold-body" }, ve)));
|
|
1964
|
+
}
|
|
1965
|
+
function ko({
|
|
1966
|
+
objects: t,
|
|
1967
|
+
extruderColors: r,
|
|
1374
1968
|
onToggleVisible: c,
|
|
1375
|
-
onExtruder:
|
|
1376
|
-
onSplit:
|
|
1377
|
-
onRemove:
|
|
1378
|
-
supportOn:
|
|
1379
|
-
onToggleSupport:
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
overhangAngle: B,
|
|
1385
|
-
paintMode: ee,
|
|
1969
|
+
onExtruder: i,
|
|
1970
|
+
onSplit: o,
|
|
1971
|
+
onRemove: p,
|
|
1972
|
+
supportOn: h,
|
|
1973
|
+
onToggleSupport: j,
|
|
1974
|
+
overhangOn: x,
|
|
1975
|
+
onToggleOverhang: B,
|
|
1976
|
+
overhangAngle: z,
|
|
1977
|
+
paintMode: m,
|
|
1386
1978
|
onTogglePaint: L,
|
|
1387
|
-
supportStyle:
|
|
1388
|
-
supportStyles:
|
|
1389
|
-
onSupportStyle:
|
|
1979
|
+
supportStyle: D,
|
|
1980
|
+
supportStyles: R,
|
|
1981
|
+
onSupportStyle: K,
|
|
1982
|
+
supportFilament: J,
|
|
1983
|
+
onSupportFilament: _,
|
|
1984
|
+
supportInterfaceFilament: T,
|
|
1985
|
+
onSupportInterfaceFilament: F,
|
|
1986
|
+
paintedObjectIds: ce
|
|
1390
1987
|
}) {
|
|
1391
|
-
|
|
1988
|
+
const pe = Number.isFinite(J) ? J : 0, w = Number.isFinite(T) ? T : 0, S = pe > 0 || w > 0, E = (y) => ce ? typeof ce.has == "function" ? ce.has(y) : Array.isArray(ce) && ce.includes(y) : !1, M = [
|
|
1989
|
+
/* @__PURE__ */ e.createElement("option", { key: "default", value: 0 }, "Default (current tool)"),
|
|
1990
|
+
...r.map((y, v) => /* @__PURE__ */ e.createElement("option", { key: v, value: v + 1 }, "T", v + 1))
|
|
1991
|
+
];
|
|
1992
|
+
return /* @__PURE__ */ e.createElement("section", { className: "side-card", "data-testid": "object-section" }, /* @__PURE__ */ e.createElement("div", { className: "sc-head" }, "📦 Objects ", /* @__PURE__ */ e.createElement("span", { className: "sc-count" }, t.length)), /* @__PURE__ */ e.createElement("ul", { className: "obj-list2", "data-testid": "obj-list" }, t.map((y) => /* @__PURE__ */ e.createElement("li", { key: y.id, className: y.visible === !1 ? "obj-hidden" : "" }, /* @__PURE__ */ e.createElement("button", { className: "obj-eye", onClick: () => c(y.id), title: "Include/exclude this object from printing — excluding it keeps it in the scene", "data-testid": `eye-${y.id}` }, /* @__PURE__ */ e.createElement("img", { src: y.visible === !1 ? Oa : Ta, alt: y.visible === !1 ? "Hidden" : "Visible" })), /* @__PURE__ */ e.createElement("span", { className: "obj-name", title: y.name }, y.name), E(y.id) && /* @__PURE__ */ e.createElement(
|
|
1993
|
+
"span",
|
|
1994
|
+
{
|
|
1995
|
+
className: "obj-painted",
|
|
1996
|
+
"data-testid": `obj-painted-${y.id}`,
|
|
1997
|
+
title: "This object has material-painted regions — the extruder below applies only to the rest of it"
|
|
1998
|
+
},
|
|
1999
|
+
"🖌"
|
|
2000
|
+
), /* @__PURE__ */ e.createElement("select", { className: "obj-ext", value: y.extruder ?? 1, onChange: (v) => i(y.id, +v.target.value), title: "Which filament (extruder) prints this object", "data-testid": `ext-${y.id}` }, r.map((v, C) => /* @__PURE__ */ e.createElement("option", { key: C, value: C + 1 }, "T", C + 1))), /* @__PURE__ */ e.createElement("button", { className: "obj-split", onClick: () => o(y.id), title: "Split to objects — every disconnected part (connected component) becomes its own object. Split to parts is not implemented (no part concept)", "data-testid": `split-${y.id}` }, /* @__PURE__ */ e.createElement("img", { src: rr, alt: "Split" })), /* @__PURE__ */ e.createElement("button", { className: "obj-del", onClick: () => p(y.id), title: "Remove this object from the scene" }, /* @__PURE__ */ e.createElement("img", { src: nr, alt: "Delete" }))))), /* @__PURE__ */ e.createElement("label", { className: "slice-support" }, /* @__PURE__ */ e.createElement("input", { type: "checkbox", checked: h, onChange: j, title: "Generate support structures under overhangs (same as enable_support in the settings panel)", "data-testid": "support-toggle" }), " Generate support"), h && /* @__PURE__ */ e.createElement("div", { className: "sc-info sup-style" }, /* @__PURE__ */ e.createElement("span", null, "Style"), /* @__PURE__ */ e.createElement(
|
|
1392
2001
|
"select",
|
|
1393
2002
|
{
|
|
1394
2003
|
className: "sc-model",
|
|
1395
|
-
value:
|
|
1396
|
-
onChange: (
|
|
2004
|
+
value: D,
|
|
2005
|
+
onChange: (y) => K(y.target.value),
|
|
1397
2006
|
"data-testid": "support-style",
|
|
1398
2007
|
title: "Support style (support_style). The kernel builds the tree/organic family as real tree support; the rest as grid."
|
|
1399
2008
|
},
|
|
1400
|
-
|
|
1401
|
-
)),
|
|
2009
|
+
R.map((y) => /* @__PURE__ */ e.createElement("option", { key: y.value, value: y.value }, y.label))
|
|
2010
|
+
)), h && _ && /* @__PURE__ */ e.createElement("div", { className: "sc-info sup-style" }, /* @__PURE__ */ e.createElement("span", null, "Filament"), /* @__PURE__ */ e.createElement(
|
|
2011
|
+
"select",
|
|
2012
|
+
{
|
|
2013
|
+
className: "sc-model",
|
|
2014
|
+
value: pe,
|
|
2015
|
+
onChange: (y) => _(+y.target.value),
|
|
2016
|
+
"data-testid": "support-filament",
|
|
2017
|
+
title: "Which filament prints the support body (support_filament). Default leaves it on whatever tool the layer is already using."
|
|
2018
|
+
},
|
|
2019
|
+
M
|
|
2020
|
+
)), h && F && /* @__PURE__ */ e.createElement("div", { className: "sc-info sup-style" }, /* @__PURE__ */ e.createElement("span", null, "Interface filament"), /* @__PURE__ */ e.createElement(
|
|
2021
|
+
"select",
|
|
2022
|
+
{
|
|
2023
|
+
className: "sc-model",
|
|
2024
|
+
value: w,
|
|
2025
|
+
onChange: (y) => F(+y.target.value),
|
|
2026
|
+
"data-testid": "support-interface-filament",
|
|
2027
|
+
title: "Which filament prints the support interface — the few layers touching the model (support_interface_filament). This is where a release material pays off."
|
|
2028
|
+
},
|
|
2029
|
+
M
|
|
2030
|
+
)), h && S && // A dedicated support tool is per-layer, not per-object: every layer that has both support and model
|
|
2031
|
+
// changes tool at least twice, so the purge volume multiplies by the layer count rather than the part count.
|
|
2032
|
+
/* @__PURE__ */ e.createElement("div", { className: "sup-filament-warn", "data-testid": "support-filament-warn" }, "⚠ Support on its own filament adds a tool change on nearly every layer — expect a much longer print and far more purge."), h && /* @__PURE__ */ e.createElement("div", { className: "support-tools" }, /* @__PURE__ */ e.createElement("label", { className: "slice-support" }, /* @__PURE__ */ e.createElement(
|
|
1402
2033
|
"input",
|
|
1403
2034
|
{
|
|
1404
2035
|
type: "checkbox",
|
|
1405
|
-
checked: !!
|
|
1406
|
-
onChange:
|
|
1407
|
-
title: `Shade the facets that will need support (slope below ${
|
|
2036
|
+
checked: !!x,
|
|
2037
|
+
onChange: B,
|
|
2038
|
+
title: `Shade the facets that will need support (slope below ${z}°, the support threshold angle)`,
|
|
1408
2039
|
"data-testid": "overhang-toggle"
|
|
1409
2040
|
}
|
|
1410
|
-
), " Show overhangs ", /* @__PURE__ */ e.createElement("span", { className: "muted" }, "<",
|
|
2041
|
+
), " Show overhangs ", /* @__PURE__ */ e.createElement("span", { className: "muted" }, "<", z, "°")), /* @__PURE__ */ e.createElement(
|
|
1411
2042
|
"button",
|
|
1412
2043
|
{
|
|
1413
|
-
className:
|
|
2044
|
+
className: m !== "off" ? "sup-paint on" : "sup-paint",
|
|
1414
2045
|
onClick: L,
|
|
1415
|
-
disabled: !
|
|
2046
|
+
disabled: !t.length,
|
|
1416
2047
|
"data-testid": "support-paint-btn",
|
|
1417
2048
|
title: "Brush facets to force or block support — the same tool as the paint icon on the left rail"
|
|
1418
2049
|
},
|
|
1419
|
-
|
|
1420
|
-
))
|
|
2050
|
+
m !== "off" ? "Painting…" : "Paint support"
|
|
2051
|
+
)));
|
|
2052
|
+
}
|
|
2053
|
+
function Jn(t, r) {
|
|
2054
|
+
const c = Array.isArray(t) ? t.map(Number) : [];
|
|
2055
|
+
return Array.from({ length: r }, (i, o) => Array.from({ length: r }, (p, h) => {
|
|
2056
|
+
const j = c[o * r + h];
|
|
2057
|
+
return Number.isFinite(j) ? j : o === h ? 0 : _o;
|
|
2058
|
+
}));
|
|
2059
|
+
}
|
|
2060
|
+
const _o = 140;
|
|
2061
|
+
function No({
|
|
2062
|
+
settings: t,
|
|
2063
|
+
setSettings: r,
|
|
2064
|
+
extruderColors: c,
|
|
2065
|
+
wipeTowerReal: i,
|
|
2066
|
+
onToggleWipeTower: o,
|
|
2067
|
+
towerStats: p
|
|
2068
|
+
}) {
|
|
2069
|
+
const h = Array.isArray(c) ? c : [], j = h.length, x = t ?? {}, B = (E) => {
|
|
2070
|
+
const M = x[E];
|
|
2071
|
+
return Array.isArray(M) ? M[0] : M;
|
|
2072
|
+
}, z = (E, M) => {
|
|
2073
|
+
const y = Number(B(E));
|
|
2074
|
+
return Number.isFinite(y) ? y : M;
|
|
2075
|
+
}, m = x.enable_prime_tower === !1, L = m ? "off" : i ? "real" : "ring", D = (E) => {
|
|
2076
|
+
r == null || r((M) => {
|
|
2077
|
+
const y = { ...M };
|
|
2078
|
+
return E === "off" ? y.enable_prime_tower = !1 : delete y.enable_prime_tower, y;
|
|
2079
|
+
}), E !== "off" && (o == null || o({ target: { checked: E === "real" } }));
|
|
2080
|
+
}, R = x.flush_into_infill === !0, K = (E) => r == null ? void 0 : r((M) => {
|
|
2081
|
+
const y = { ...M };
|
|
2082
|
+
return E ? y.flush_into_infill = !0 : delete y.flush_into_infill, y;
|
|
2083
|
+
}), J = z("prime_tower_width", 0), _ = B("wipe_tower_x"), T = B("wipe_tower_y"), F = Number.isFinite(Number(_)) && String(_) !== "", ce = (E, M) => r == null ? void 0 : r((y) => {
|
|
2084
|
+
const v = { ...y };
|
|
2085
|
+
return M === null || M === "" || !Number.isFinite(Number(M)) ? delete v[E] : v[E] = Number(M), v;
|
|
2086
|
+
}), pe = (E, M) => r == null ? void 0 : r((y) => {
|
|
2087
|
+
const v = { ...y };
|
|
2088
|
+
return E === null ? (delete v.wipe_tower_x, delete v.wipe_tower_y, v) : (v.wipe_tower_x = Number(E), v.wipe_tower_y = Number(M), v);
|
|
2089
|
+
}), w = Jn(x.flush_volumes_matrix, j), S = (E, M, y) => r == null ? void 0 : r((v) => {
|
|
2090
|
+
const C = { ...v }, V = Jn(v == null ? void 0 : v.flush_volumes_matrix, j);
|
|
2091
|
+
return V[E][M] = Math.max(0, Number(y) || 0), C.flush_volumes_matrix = V.flat(), C;
|
|
2092
|
+
});
|
|
2093
|
+
return /* @__PURE__ */ e.createElement("section", { className: "side-card", "data-testid": "tower-section" }, /* @__PURE__ */ e.createElement("div", { className: "sc-head" }, "🗼 Prime tower"), /* @__PURE__ */ e.createElement("div", { className: "sc-info" }, /* @__PURE__ */ e.createElement("span", null, "Mode"), /* @__PURE__ */ e.createElement("select", { className: "sc-model", "data-testid": "tower-mode", value: L, onChange: (E) => D(E.target.value) }, /* @__PURE__ */ e.createElement("option", { value: "ring" }, "Ring — deterministic"), /* @__PURE__ */ e.createElement("option", { value: "real" }, "Real wipe tower — not reproducible yet"), /* @__PURE__ */ e.createElement("option", { value: "off" }, "Off — no tower"))), /* @__PURE__ */ e.createElement("div", { className: "sc-info" }, /* @__PURE__ */ e.createElement("span", null, "Purge into"), /* @__PURE__ */ e.createElement(
|
|
2094
|
+
"select",
|
|
2095
|
+
{
|
|
2096
|
+
className: "sc-model",
|
|
2097
|
+
"data-testid": "tower-flush",
|
|
2098
|
+
value: R ? "infill" : "tower",
|
|
2099
|
+
onChange: (E) => K(E.target.value === "infill"),
|
|
2100
|
+
title: "Infill hides the purge inside the part; a layer with no sparse infill still needs the tower."
|
|
2101
|
+
},
|
|
2102
|
+
/* @__PURE__ */ e.createElement("option", { value: "tower" }, "The tower"),
|
|
2103
|
+
/* @__PURE__ */ e.createElement("option", { value: "infill" }, "The model's infill")
|
|
2104
|
+
)), m && !R && /* @__PURE__ */ e.createElement("div", { className: "bp-note", "data-testid": "tower-off-warning" }, "With no tower and no flush destination, a tool change carries the previous colour into the model."), L !== "off" && /* @__PURE__ */ e.createElement("div", { className: "sc-info" }, /* @__PURE__ */ e.createElement("span", null, "Width"), /* @__PURE__ */ e.createElement("span", { className: "sc-num" }, /* @__PURE__ */ e.createElement(
|
|
2105
|
+
"input",
|
|
2106
|
+
{
|
|
2107
|
+
type: "number",
|
|
2108
|
+
min: "5",
|
|
2109
|
+
max: "150",
|
|
2110
|
+
step: "1",
|
|
2111
|
+
value: J || "",
|
|
2112
|
+
placeholder: "auto",
|
|
2113
|
+
"data-testid": "tower-width",
|
|
2114
|
+
title: "Footprint of the tower (mm). Empty uses the slicer's own default.",
|
|
2115
|
+
onChange: (E) => ce("prime_tower_width", E.target.value)
|
|
2116
|
+
}
|
|
2117
|
+
), " mm")), L !== "off" && /* @__PURE__ */ e.createElement("div", { className: "sc-info" }, /* @__PURE__ */ e.createElement("span", null, "Position"), /* @__PURE__ */ e.createElement(
|
|
2118
|
+
"select",
|
|
2119
|
+
{
|
|
2120
|
+
className: "sc-model",
|
|
2121
|
+
"data-testid": "tower-position-mode",
|
|
2122
|
+
value: F ? "manual" : "auto",
|
|
2123
|
+
onChange: (E) => pe(E.target.value === "auto" ? null : (p == null ? void 0 : p.x) ?? 10, (p == null ? void 0 : p.y) ?? 10),
|
|
2124
|
+
title: "Auto places the tower beside the model; manual pins it to a bed coordinate."
|
|
2125
|
+
},
|
|
2126
|
+
/* @__PURE__ */ e.createElement("option", { value: "auto" }, "Beside the model"),
|
|
2127
|
+
/* @__PURE__ */ e.createElement("option", { value: "manual" }, "Fixed coordinate")
|
|
2128
|
+
)), L !== "off" && F && /* @__PURE__ */ e.createElement("div", { className: "sc-info" }, /* @__PURE__ */ e.createElement("span", null, "X / Y"), /* @__PURE__ */ e.createElement("span", { className: "sc-num" }, /* @__PURE__ */ e.createElement(
|
|
2129
|
+
"input",
|
|
2130
|
+
{
|
|
2131
|
+
type: "number",
|
|
2132
|
+
step: "1",
|
|
2133
|
+
value: Number(_),
|
|
2134
|
+
"data-testid": "tower-x",
|
|
2135
|
+
onChange: (E) => pe(E.target.value, Number(T) || 0)
|
|
2136
|
+
}
|
|
2137
|
+
), /* @__PURE__ */ e.createElement(
|
|
2138
|
+
"input",
|
|
2139
|
+
{
|
|
2140
|
+
type: "number",
|
|
2141
|
+
step: "1",
|
|
2142
|
+
value: Number(T) || 0,
|
|
2143
|
+
"data-testid": "tower-y",
|
|
2144
|
+
onChange: (E) => pe(Number(_) || 0, E.target.value)
|
|
2145
|
+
}
|
|
2146
|
+
), " mm")), j > 1 && /* @__PURE__ */ e.createElement("details", { className: "sc-fold", "data-testid": "tower-purge-fold" }, /* @__PURE__ */ e.createElement("summary", null, /* @__PURE__ */ e.createElement("span", { className: "sc-fold-lbl" }, "Purging volumes"), /* @__PURE__ */ e.createElement("b", null, "mm³")), /* @__PURE__ */ e.createElement("div", { className: "sc-fold-body" }, /* @__PURE__ */ e.createElement("table", { className: "purge-grid", "data-testid": "purge-matrix" }, /* @__PURE__ */ e.createElement("thead", null, /* @__PURE__ */ e.createElement("tr", null, /* @__PURE__ */ e.createElement("th", null), h.map((E, M) => /* @__PURE__ */ e.createElement("th", { key: M }, /* @__PURE__ */ e.createElement("span", { className: "stat-swatch", style: { background: E } }), "T", M + 1)))), /* @__PURE__ */ e.createElement("tbody", null, h.map((E, M) => /* @__PURE__ */ e.createElement("tr", { key: M }, /* @__PURE__ */ e.createElement("th", null, /* @__PURE__ */ e.createElement("span", { className: "stat-swatch", style: { background: E } }), "T", M + 1), h.map((y, v) => /* @__PURE__ */ e.createElement("td", { key: v }, M === v ? /* @__PURE__ */ e.createElement("span", { className: "muted" }, "—") : /* @__PURE__ */ e.createElement(
|
|
2147
|
+
"input",
|
|
2148
|
+
{
|
|
2149
|
+
type: "number",
|
|
2150
|
+
min: "0",
|
|
2151
|
+
step: "10",
|
|
2152
|
+
value: w[M][v],
|
|
2153
|
+
"data-testid": `purge-${M}-${v}`,
|
|
2154
|
+
onChange: (C) => S(M, v, C.target.value)
|
|
2155
|
+
}
|
|
2156
|
+
))))))), /* @__PURE__ */ e.createElement("div", { className: "muted bp-note" }, "Volume pushed out when the print switches from the row's filament to the column's. A dark colour following a light one needs more."))), p && /* @__PURE__ */ e.createElement("div", { className: "muted bp-counts", "data-testid": "tower-stats" }, "last slice: ", p.changes, " tool change", p.changes === 1 ? "" : "s", " ·", " ", p.purge.toFixed(1), " mm purged", Number.isFinite(p.x) && ` · at ${p.x.toFixed(0)}, ${p.y.toFixed(0)}`));
|
|
1421
2157
|
}
|
|
1422
|
-
function
|
|
1423
|
-
autoSlice:
|
|
1424
|
-
onAutoSlice:
|
|
2158
|
+
function Mo({
|
|
2159
|
+
autoSlice: t,
|
|
2160
|
+
onAutoSlice: r,
|
|
1425
2161
|
slicing: c,
|
|
1426
|
-
progress:
|
|
1427
|
-
plateCount:
|
|
1428
|
-
selectedPlate:
|
|
1429
|
-
sliceMenuOpen:
|
|
1430
|
-
onSliceMenu:
|
|
1431
|
-
slicedPlateCount:
|
|
1432
|
-
canSlice:
|
|
1433
|
-
onSlice:
|
|
1434
|
-
onCancel:
|
|
1435
|
-
onExportAll:
|
|
1436
|
-
gcodeUrl:
|
|
2162
|
+
progress: i,
|
|
2163
|
+
plateCount: o,
|
|
2164
|
+
selectedPlate: p,
|
|
2165
|
+
sliceMenuOpen: h,
|
|
2166
|
+
onSliceMenu: j,
|
|
2167
|
+
slicedPlateCount: x,
|
|
2168
|
+
canSlice: B,
|
|
2169
|
+
onSlice: z,
|
|
2170
|
+
onCancel: m,
|
|
2171
|
+
onExportAll: L,
|
|
2172
|
+
gcodeUrl: D
|
|
1437
2173
|
}) {
|
|
1438
|
-
const
|
|
1439
|
-
return /* @__PURE__ */ e.createElement("div", { className: "side-bottom" }, /* @__PURE__ */ e.createElement("label", { className: "auto-slice", "data-testid": "auto-slice", title: "Re-slice automatically 0.8s after a settings change (the first slice is manual; a running slice is canceled and restarted)" }, /* @__PURE__ */ e.createElement("input", { type: "checkbox", checked:
|
|
2174
|
+
const R = c ? "Click to cancel the slice" : o > 1 ? "Choose what to slice (Ctrl+R = current plate)" : "Slice the current plate (Ctrl+R)";
|
|
2175
|
+
return /* @__PURE__ */ e.createElement("div", { className: "side-bottom" }, /* @__PURE__ */ e.createElement("label", { className: "auto-slice", "data-testid": "auto-slice", title: "Re-slice automatically 0.8s after a settings change (the first slice is manual; a running slice is canceled and restarted)" }, /* @__PURE__ */ e.createElement("input", { type: "checkbox", checked: t, onChange: (K) => r(K.target.checked) }), " Auto slice"), /* @__PURE__ */ e.createElement("div", { className: "slice-dd" }, /* @__PURE__ */ e.createElement(
|
|
1440
2176
|
"button",
|
|
1441
2177
|
{
|
|
1442
2178
|
className: "slice-btn",
|
|
1443
|
-
title:
|
|
1444
|
-
onClick: () => c ?
|
|
1445
|
-
disabled: !
|
|
2179
|
+
title: R,
|
|
2180
|
+
onClick: () => c ? m() : o > 1 ? j() : z("current"),
|
|
2181
|
+
disabled: !B,
|
|
1446
2182
|
"data-testid": "slice-btn"
|
|
1447
2183
|
},
|
|
1448
|
-
c ? `Slicing… ${Math.round(
|
|
1449
|
-
),
|
|
2184
|
+
c ? `Slicing… ${Math.round(i * 100)}%` : o > 1 ? "Slice ▾" : "Slice"
|
|
2185
|
+
), h && o > 1 && /* @__PURE__ */ e.createElement("div", { className: "slice-menu", "data-testid": "slice-menu" }, /* @__PURE__ */ e.createElement("button", { onClick: () => z("current"), "data-testid": "slice-current", title: "Slice only the selected plate (Ctrl+R)" }, "Current plate (P", p + 1, ")"), /* @__PURE__ */ e.createElement("button", { onClick: () => z("all"), "data-testid": "slice-all", title: "Slice every plate in turn — switch tabs to inspect the results" }, "All plates (", o, ")"), x > 0 && /* @__PURE__ */ e.createElement("button", { onClick: L, "data-testid": "export-all", title: "Save the G-code of every sliced plate as its own file" }, "Export all G-code (", x, ")"))), D ? /* @__PURE__ */ e.createElement("a", { className: "export-btn", href: D, download: `plate_${p + 1}.gcode`, title: "Save the G-code of the plate you are viewing", "data-testid": "gcode-dl" }, "Export G-code") : /* @__PURE__ */ e.createElement("button", { className: "export-btn", disabled: !0, title: "Export G-code — enabled after slicing" }, "Export G-code"));
|
|
1450
2186
|
}
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
}
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
2187
|
+
const Qn = [
|
|
2188
|
+
"#6aa0dc",
|
|
2189
|
+
"#e08a2b",
|
|
2190
|
+
"#e0473b",
|
|
2191
|
+
"#3bb0e0",
|
|
2192
|
+
"#7ad14a",
|
|
2193
|
+
"#b06ad1",
|
|
2194
|
+
"#d1c34a",
|
|
2195
|
+
"#4ad1a8",
|
|
2196
|
+
"#d16a9a",
|
|
2197
|
+
"#6a7ad1",
|
|
2198
|
+
"#8fd16a",
|
|
2199
|
+
"#d18f6a",
|
|
2200
|
+
"#6ad1d1",
|
|
2201
|
+
"#c74ad1",
|
|
2202
|
+
"#a8a8a8",
|
|
2203
|
+
"#4a6ad1"
|
|
2204
|
+
];
|
|
2205
|
+
function Fo({
|
|
2206
|
+
settings: t = {},
|
|
2207
|
+
setSettings: r = () => {
|
|
2208
|
+
},
|
|
2209
|
+
processPanel: c = null,
|
|
2210
|
+
motionPanel: i = null,
|
|
2211
|
+
filamentPanel: o = null,
|
|
2212
|
+
panels: p = null,
|
|
2213
|
+
gcode: h = null,
|
|
2214
|
+
defaultExtruderColors: j = null,
|
|
2215
|
+
defaultAutoSlice: x = !1,
|
|
2216
|
+
onEvent: B = null,
|
|
2217
|
+
onSliced: z = null
|
|
2218
|
+
}) {
|
|
2219
|
+
var zn, Rn, Tn, On, Ln, Sn, Fn;
|
|
2220
|
+
const m = (n) => (p == null ? void 0 : p[n]) !== !1, L = ne(B);
|
|
2221
|
+
L.current = B;
|
|
2222
|
+
const D = ne(z);
|
|
2223
|
+
D.current = z;
|
|
2224
|
+
const R = ne(null), K = ne(null), J = ne([]), _ = ne(null), T = ne(null), F = ne(null), ce = ne({}), pe = ne(null), w = ne(null), S = ne(!1), E = ne("feature"), M = ne(0), y = ne(0), v = ne("prepare"), C = ne(0.42), V = ne("off"), f = ne(0), N = ne(5), O = ne(null), H = ne(null), oe = ne(null), ue = ne(null), $ = ne({}), P = ne({}), ve = ne(0), Me = ne(1), ge = ne(0), [Ee, b] = ae(!0), [k, G] = ae("translate"), [q, s] = ae("Initializing…"), [d, A] = ae([]), [u, I] = ae(""), [se, ye] = ae(!1), [xe, je] = ae(!!x), Q = ne(0), [Z, ee] = ae(0), [he, me] = ae(""), [fe, le] = ae(null), [Ae, Pe] = ae(!1), [Re, qe] = ae(0), [dt, Xe] = ae(0), [Je, Nt] = ae(1), [$e, Mt] = ae(0), [At, Ct] = ae(!1), [mt, ft] = ae(!1), [at, ht] = ae(0), [bt, gt] = ae(null), [yt, xt] = ae("feature"), [jt, a] = ae(null), [l, U] = ae(0), [Y, re] = ae(0), [X, ke] = ae(!1), [ze, Ce] = ae([]), [be, Se] = ae("prepare"), [Ve, ot] = ae(!1), Ue = ne(null), lt = Array.isArray(j) && j.length ? j.slice(0, $t) : Qn.slice(0, 2), [we, _e] = ae(lt), Le = ne(lt), [Ie, We] = ae(""), [Qe, Ye] = ae(!1), [et, vt] = ae(!1), [de, Fe] = ae("off"), [Zt, st] = ae(0), [tt, Vt] = ae(5), [Pt, sn] = ae("brush"), [zt, cn] = ae("sphere"), [Rt, dn] = ae(30), pn = ne({ tool: "brush", cursor: "sphere", angle: 30 });
|
|
2225
|
+
Te(() => {
|
|
2226
|
+
pn.current = { tool: Pt, cursor: zt, angle: Rt };
|
|
2227
|
+
}, [Pt, zt, Rt]);
|
|
2228
|
+
const [Gt, un] = ae({ enf: 0, blk: 0 }), [Ut, lr] = ae({}), mn = ne({});
|
|
2229
|
+
Te(() => {
|
|
2230
|
+
mn.current = Ut;
|
|
2231
|
+
}, [Ut]);
|
|
2232
|
+
const [Wt, pt] = ae(""), [fn, hn] = ae(null), Ze = (n, g) => {
|
|
2233
|
+
const te = ne(!0);
|
|
2234
|
+
Te(() => {
|
|
2235
|
+
var ie;
|
|
2236
|
+
if (te.current) {
|
|
2237
|
+
te.current = !1;
|
|
2238
|
+
return;
|
|
2239
|
+
}
|
|
2240
|
+
(ie = L.current) == null || ie.call(L, { type: n, value: g });
|
|
2241
|
+
}, [g]);
|
|
2242
|
+
};
|
|
2243
|
+
Ze("canvasMode", be), Ze("objects", d), Ze("selectedPlate", $e), Ze("plateCount", Je), Ze("extruderColors", we), Ze("autoSlice", xe), Ze("slicing", se), Ze("progress", Z), Ze("viewType", yt), Ze("paintMode", de), Ze("layerCount", Re), Ze("error", he), Ze("notice", Wt);
|
|
2244
|
+
const bn = ne(!0);
|
|
2245
|
+
Te(() => {
|
|
2246
|
+
var n;
|
|
2247
|
+
if (bn.current) {
|
|
2248
|
+
bn.current = !1;
|
|
2249
|
+
return;
|
|
2250
|
+
}
|
|
2251
|
+
(n = L.current) == null || n.call(L, { type: "layerRange", value: { lo: l, hi: Y } });
|
|
2252
|
+
}, [l, Y]);
|
|
2253
|
+
const { mountRef: sr, three: Tt } = Ja({
|
|
2254
|
+
apiRef: R,
|
|
2255
|
+
objectsRef: J,
|
|
2256
|
+
keyRef: pe,
|
|
2257
|
+
workerRef: K,
|
|
2258
|
+
selectedPlateRef: ve,
|
|
2259
|
+
placeXRef: ge,
|
|
2260
|
+
plateCountRef: Me,
|
|
2261
|
+
canvasModeRef: v,
|
|
2262
|
+
paintModeRef: V,
|
|
2263
|
+
brushRadiusRef: N,
|
|
2264
|
+
paintToolRef: pn,
|
|
2265
|
+
paintXformRef: O,
|
|
2266
|
+
paintOverlayRef: H,
|
|
2267
|
+
extruderColorsRef: Le,
|
|
2268
|
+
setOk: b,
|
|
2269
|
+
setStatus: s,
|
|
2270
|
+
setGmode: G,
|
|
2271
|
+
setCtxMenu: gt,
|
|
2272
|
+
setBrushRadius: Vt,
|
|
2273
|
+
// Dragging the tower box is how a position becomes chosen: it writes the same wipe_tower_x/y the card edits,
|
|
2274
|
+
// so the two controls are one setting seen two ways.
|
|
2275
|
+
// The drop lands in world coordinates and the setting is a bed coordinate, so the plate's origin comes back
|
|
2276
|
+
// off — the same conversion the box's placement makes going the other way.
|
|
2277
|
+
// A move/rotate/scale changes the coordinates the kernel's selector holds, so it has to be handed the new
|
|
2278
|
+
// ones — otherwise the overlay stays where the model was and a slice projects the paint there too. Gated on
|
|
2279
|
+
// the selector EXISTING, not on paint mode being on: in paint mode the gizmo is detached, so every real move
|
|
2280
|
+
// happens with the panel closed — a paint-mode gate would never fire. Through a ref because the paint module
|
|
2281
|
+
// is built further down and this handler is installed once.
|
|
2282
|
+
onTransformCommitted: () => {
|
|
2283
|
+
var n;
|
|
2284
|
+
oe.current && ((n = ue.current) == null || n.call(ue));
|
|
2285
|
+
},
|
|
2286
|
+
onTowerMoved: (n, g) => {
|
|
2287
|
+
var ie, Ne;
|
|
2288
|
+
const te = ((Ne = (ie = R.current) == null ? void 0 : ie.platePos) == null ? void 0 : Ne.call(ie, ve.current)) ?? { x: 0, z: 0 };
|
|
2289
|
+
r((Be) => ({
|
|
2290
|
+
...Be,
|
|
2291
|
+
wipe_tower_x: Math.round((n - te.x + Ht.current.bedW / 2) * 10) / 10,
|
|
2292
|
+
wipe_tower_y: Math.round((g + te.z + Ht.current.bedD / 2) * 10) / 10
|
|
2293
|
+
}));
|
|
2294
|
+
}
|
|
2295
|
+
}), Oe = ln(t), Ht = ne({ bedW: 200, bedD: 200 });
|
|
2296
|
+
Ht.current = { bedW: Oe.bed_width, bedD: Oe.bed_depth }, Te(() => {
|
|
2297
|
+
var n;
|
|
2298
|
+
(n = R.current) == null || n.setPlates(Je, Oe.bed_width, Oe.bed_depth, $e);
|
|
2299
|
+
}, [Oe.bed_width, Oe.bed_depth, Je, $e]), Te(() => {
|
|
2300
|
+
var In, Zn, Vn, Gn;
|
|
2301
|
+
const n = R.current;
|
|
2302
|
+
if (!n) return;
|
|
2303
|
+
const g = we.length > 1, te = (t == null ? void 0 : t.enable_prime_tower) === !1;
|
|
2304
|
+
if (!g || te || be !== "prepare" || d.length === 0) {
|
|
2305
|
+
(In = n.setPrimeTower) == null || In.call(n, null);
|
|
2306
|
+
return;
|
|
2307
|
+
}
|
|
2308
|
+
const ie = et ? Number(He(t, "prime_tower_width")) || 30 : 15, Ne = (Zn = n.modelBounds) == null ? void 0 : Zn.call(n, $e), Be = Oe.bed_width, De = Oe.bed_depth, Ke = ((Vn = n.platePos) == null ? void 0 : Vn.call(n, $e)) ?? { x: 0, z: 0 }, wt = (nn) => {
|
|
2309
|
+
const ct = t == null ? void 0 : t[nn], Lt = Number(Array.isArray(ct) ? ct[0] : ct);
|
|
2310
|
+
return ct != null && ct !== "" && Number.isFinite(Lt) ? Lt : NaN;
|
|
2311
|
+
}, Bn = wt("wipe_tower_x"), Qr = wt("wipe_tower_y"), Dn = !Number.isFinite(Bn), ea = 5, $n = (nn, ct, Lt) => Math.min(Math.max(nn, ct), Lt), ta = Dn ? Ke.x + $n((Ne ? Ne.minX - Ke.x : 0) - ea - ie / 2, -Be / 2 + ie / 2, Be / 2 - ie / 2) : Ke.x + Bn - Be / 2 + ie / 2, na = Dn ? -Ke.z + $n(Ne ? (Ne.minY + Ne.maxY) / 2 + Ke.z : 0, -De / 2 + ie / 2, De / 2 - ie / 2) : -Ke.z + Qr - De / 2 + ie / 2, ra = Math.max(2, (Ne == null ? void 0 : Ne.height) ?? 20);
|
|
2312
|
+
(Gn = n.setPrimeTower) == null || Gn.call(n, { x: ta, y: na, size: ie, height: ra });
|
|
2313
|
+
}, [we.length, be, d.length, et, t, $e, Oe.bed_width, Oe.bed_depth]), Te(() => {
|
|
2314
|
+
var te;
|
|
2315
|
+
v.current = be;
|
|
2316
|
+
const n = Tt.current;
|
|
2317
|
+
if (!n.toolpathGroup) return;
|
|
2318
|
+
const g = be === "preview";
|
|
2319
|
+
n.toolpathGroup.visible = g, n.objectsGroup && (n.objectsGroup.visible = !g && J.current.length > 0), g && ((te = R.current) == null || te.detachTransform(), V.current !== "off" && nt("off"));
|
|
2320
|
+
}, [be]);
|
|
1484
2321
|
const {
|
|
1485
|
-
disposePlateToolpath:
|
|
1486
|
-
clearToolpaths:
|
|
1487
|
-
buildPlateToolpath:
|
|
1488
|
-
ensurePlateToolpaths:
|
|
1489
|
-
applyViewColors:
|
|
1490
|
-
rebuildToolpaths:
|
|
1491
|
-
applyLayerRange:
|
|
1492
|
-
} =
|
|
1493
|
-
three:
|
|
1494
|
-
plateTpRef:
|
|
1495
|
-
toolpathRef:
|
|
1496
|
-
segDataRef:
|
|
1497
|
-
layersDataRef:
|
|
1498
|
-
plateResultsRef:
|
|
1499
|
-
plateOffsetsRef:
|
|
1500
|
-
lineWidthRef:
|
|
1501
|
-
showTravelRef:
|
|
1502
|
-
viewTypeRef:
|
|
1503
|
-
layerLoRef:
|
|
1504
|
-
layerHiRef:
|
|
1505
|
-
selectedPlateRef:
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
}
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
2322
|
+
disposePlateToolpath: ir,
|
|
2323
|
+
clearToolpaths: cr,
|
|
2324
|
+
buildPlateToolpath: dr,
|
|
2325
|
+
ensurePlateToolpaths: pr,
|
|
2326
|
+
applyViewColors: Ot,
|
|
2327
|
+
rebuildToolpaths: ur,
|
|
2328
|
+
applyLayerRange: mr
|
|
2329
|
+
} = eo({
|
|
2330
|
+
three: Tt,
|
|
2331
|
+
plateTpRef: ce,
|
|
2332
|
+
toolpathRef: T,
|
|
2333
|
+
segDataRef: F,
|
|
2334
|
+
layersDataRef: _,
|
|
2335
|
+
plateResultsRef: $,
|
|
2336
|
+
plateOffsetsRef: P,
|
|
2337
|
+
lineWidthRef: C,
|
|
2338
|
+
showTravelRef: S,
|
|
2339
|
+
viewTypeRef: E,
|
|
2340
|
+
layerLoRef: M,
|
|
2341
|
+
layerHiRef: y,
|
|
2342
|
+
selectedPlateRef: ve,
|
|
2343
|
+
extruderColorsRef: Le,
|
|
2344
|
+
settings: t,
|
|
2345
|
+
setSegCount: Xe,
|
|
2346
|
+
setColorRange: a,
|
|
2347
|
+
setRoleLegend: Ce
|
|
2348
|
+
}), { getWorker: fr, cancelSlice: gn, runSlice: hr, pendingSliceRef: br, downgradeRef: gr } = Qa({
|
|
2349
|
+
settings: t,
|
|
2350
|
+
wipeTowerReal: et,
|
|
2351
|
+
workerRef: K,
|
|
2352
|
+
apiRef: R,
|
|
2353
|
+
layersDataRef: _,
|
|
2354
|
+
layerLoRef: M,
|
|
2355
|
+
layerHiRef: y,
|
|
2356
|
+
paintStateCountsRef: mn,
|
|
2357
|
+
rebuildToolpaths: ur,
|
|
2358
|
+
rebuildPaintOverlay: (n, g, te) => yr(n, g, te),
|
|
2359
|
+
setProgress: ee,
|
|
2360
|
+
setSlicing: ye,
|
|
2361
|
+
setError: me,
|
|
2362
|
+
setStats: le,
|
|
2363
|
+
setOverBed: Pe,
|
|
2364
|
+
setLayerCount: qe,
|
|
2365
|
+
setLayerLo: U,
|
|
2366
|
+
setLayerHi: re,
|
|
2367
|
+
setGcodeUrl: We,
|
|
2368
|
+
setCanvasMode: Se,
|
|
2369
|
+
setPaintCounts: un,
|
|
2370
|
+
setSliceNotice: pt
|
|
2371
|
+
}), { rebuildPaintOverlay: yr, setPaintMode: nt, clearPaint: yn, registerSelector: xr } = ao({
|
|
2372
|
+
three: Tt,
|
|
2373
|
+
objectsRef: J,
|
|
2374
|
+
apiRef: R,
|
|
2375
|
+
getWorker: fr,
|
|
2376
|
+
selectedPlateRef: ve,
|
|
2377
|
+
selectorGeomRef: oe,
|
|
2378
|
+
paintXformRef: O,
|
|
2379
|
+
paintOverlayRef: H,
|
|
2380
|
+
paintModeRef: V,
|
|
2381
|
+
materialExtruderRef: f,
|
|
2382
|
+
extruderColorsRef: Le,
|
|
2383
|
+
setError: me,
|
|
2384
|
+
setPaintModeState: Fe,
|
|
2385
|
+
setPaintCounts: un,
|
|
2386
|
+
setPaintStateCounts: lr,
|
|
2387
|
+
setSliceNotice: pt
|
|
2388
|
+
});
|
|
2389
|
+
ue.current = xr;
|
|
2390
|
+
const {
|
|
2391
|
+
showPlateResult: vr,
|
|
2392
|
+
refreshSlicedCount: xn,
|
|
2393
|
+
exportAllGcode: wr,
|
|
2394
|
+
onSlice: qt,
|
|
2395
|
+
retryDowngrade: Er,
|
|
2396
|
+
addPlate: kr,
|
|
2397
|
+
deletePlate: _r,
|
|
2398
|
+
selectPlate: Nr
|
|
2399
|
+
} = to({
|
|
2400
|
+
onSlicedRef: D,
|
|
2401
|
+
apiRef: R,
|
|
2402
|
+
selectedPlateRef: ve,
|
|
2403
|
+
plateCountRef: Me,
|
|
2404
|
+
placeXRef: ge,
|
|
2405
|
+
plateResultsRef: $,
|
|
2406
|
+
plateOffsetsRef: P,
|
|
2407
|
+
plateTpRef: ce,
|
|
2408
|
+
layersDataRef: _,
|
|
2409
|
+
toolpathRef: T,
|
|
2410
|
+
segDataRef: F,
|
|
2411
|
+
layerLoRef: M,
|
|
2412
|
+
layerHiRef: y,
|
|
2413
|
+
lineWidthRef: C,
|
|
2414
|
+
downgradeRef: gr,
|
|
2415
|
+
settings: t,
|
|
2416
|
+
canvasMode: be,
|
|
2417
|
+
downgradeOffer: fn,
|
|
2418
|
+
runSlice: hr,
|
|
2419
|
+
ensurePlateToolpaths: pr,
|
|
2420
|
+
buildPlateToolpath: dr,
|
|
2421
|
+
applyViewColors: Ot,
|
|
2422
|
+
disposePlateToolpath: ir,
|
|
2423
|
+
setStats: le,
|
|
2424
|
+
setOverBed: Pe,
|
|
2425
|
+
setLayerCount: qe,
|
|
2426
|
+
setSegCount: Xe,
|
|
2427
|
+
setColorRange: a,
|
|
2428
|
+
setRoleLegend: Ce,
|
|
2429
|
+
setGcodeUrl: We,
|
|
2430
|
+
setLayerLo: U,
|
|
2431
|
+
setLayerHi: re,
|
|
2432
|
+
setCanvasMode: Se,
|
|
2433
|
+
setSlicedPlateCount: ht,
|
|
2434
|
+
setSliceMenu: Ct,
|
|
2435
|
+
setError: me,
|
|
2436
|
+
setSliceNotice: pt,
|
|
2437
|
+
setDowngradeOffer: hn,
|
|
2438
|
+
setSlicing: ye,
|
|
2439
|
+
setProgress: ee,
|
|
2440
|
+
setPlateCount: Nt,
|
|
2441
|
+
setSelectedPlate: Mt,
|
|
2442
|
+
// Belt to the commit hook's braces: a move can reach a slice without a gizmo commit (keyboard nudge, plate
|
|
2443
|
+
// re-arrange), so the slice itself hands the selector the mesh it is about to cut. Only for the selected
|
|
2444
|
+
// plate — that is the mesh the brush painted — and only when a selector exists at all.
|
|
2445
|
+
syncPaintSelector: (n) => {
|
|
2446
|
+
var g;
|
|
2447
|
+
oe.current && ((g = ue.current) == null || g.call(ue, n));
|
|
2448
|
+
}
|
|
2449
|
+
}), { onFiles: Mr, removeObject: vn, onDrop: Ar, onDragOver: Cr, onDragLeave: jr } = no({
|
|
2450
|
+
apiRef: R,
|
|
2451
|
+
objectsRef: J,
|
|
2452
|
+
layersDataRef: _,
|
|
2453
|
+
segDataRef: F,
|
|
2454
|
+
plateResultsRef: $,
|
|
2455
|
+
plateOffsetsRef: P,
|
|
2456
|
+
clearToolpaths: cr,
|
|
2457
|
+
refreshSlicedCount: xn,
|
|
2458
|
+
dragOver: Ve,
|
|
2459
|
+
setError: me,
|
|
2460
|
+
setTriWarn: I,
|
|
2461
|
+
setProgress: ee,
|
|
2462
|
+
setStats: le,
|
|
2463
|
+
setOverBed: Pe,
|
|
2464
|
+
setLayerCount: qe,
|
|
2465
|
+
setSegCount: Xe,
|
|
2466
|
+
setColorRange: a,
|
|
2467
|
+
setSliceNotice: pt,
|
|
2468
|
+
setDowngradeOffer: hn,
|
|
2469
|
+
setGcodeUrl: We,
|
|
2470
|
+
setCanvasMode: Se,
|
|
2471
|
+
setObjects: A,
|
|
2472
|
+
setDragOver: ot
|
|
1617
2473
|
});
|
|
1618
|
-
|
|
1619
|
-
if (!
|
|
1620
|
-
clearTimeout(
|
|
1621
|
-
const
|
|
1622
|
-
if (
|
|
1623
|
-
|
|
2474
|
+
Te(() => {
|
|
2475
|
+
if (!xe || !d.length || h != null) return;
|
|
2476
|
+
clearTimeout(Q.current);
|
|
2477
|
+
const n = () => {
|
|
2478
|
+
if (br.current) {
|
|
2479
|
+
gn(), Q.current = setTimeout(n, 300);
|
|
1624
2480
|
return;
|
|
1625
2481
|
}
|
|
1626
|
-
|
|
2482
|
+
qt("current");
|
|
1627
2483
|
};
|
|
1628
|
-
return
|
|
1629
|
-
}, [
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
}
|
|
1647
|
-
function
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
}
|
|
1668
|
-
function
|
|
1669
|
-
const
|
|
1670
|
-
|
|
1671
|
-
}
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
}
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
(
|
|
1679
|
-
}
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
2484
|
+
return Q.current = setTimeout(n, 800), () => clearTimeout(Q.current);
|
|
2485
|
+
}, [t, xe, d.length]), Te(() => {
|
|
2486
|
+
if (h == null) return;
|
|
2487
|
+
const n = ve.current;
|
|
2488
|
+
try {
|
|
2489
|
+
const g = ba(String(h), { filamentDiameter: Number(Oe.filament_diameter) || 1.75 });
|
|
2490
|
+
if (!g.layers.length) {
|
|
2491
|
+
me("No printable moves found in the G-code");
|
|
2492
|
+
return;
|
|
2493
|
+
}
|
|
2494
|
+
const te = Ft(Me.current), ie = Oe.bed_width, Ne = Oe.bed_depth;
|
|
2495
|
+
P.current[n] = {
|
|
2496
|
+
offX: n % te * rt(ie) - ie / 2,
|
|
2497
|
+
offZ: Math.floor(n / te) * rt(Ne) + Ne / 2
|
|
2498
|
+
}, C.current = Oe.line_width || 0.42, $.current[n] = { stats: g.stats, layers: g.layers, gcode: String(h) }, xn(), me(""), pt(""), vr(n);
|
|
2499
|
+
} catch (g) {
|
|
2500
|
+
me("G-code parse failed: " + ((g == null ? void 0 : g.message) || g));
|
|
2501
|
+
}
|
|
2502
|
+
}, [h]);
|
|
2503
|
+
function Pr(n, g) {
|
|
2504
|
+
if (!(n > 0) || !(g > 0)) return;
|
|
2505
|
+
const te = He(t, "printable_area"), ie = Array.isArray(te) && te.length >= 3, Ne = ie ? Math.min(...te.map((De) => De[0])) : 0, Be = ie ? Math.min(...te.map((De) => De[1])) : 0;
|
|
2506
|
+
r((De) => ({ ...De, printable_area: [[Ne, Be], [Ne + n, Be], [Ne + n, Be + g], [Ne, Be + g]] }));
|
|
2507
|
+
}
|
|
2508
|
+
function zr(n, g) {
|
|
2509
|
+
var te;
|
|
2510
|
+
(te = R.current) == null || te.setObjectExtruder(n, g), A(J.current.map((ie) => ({ id: ie.id, name: ie.name, extruder: ie.extruder, visible: ie.visible !== !1 })));
|
|
2511
|
+
}
|
|
2512
|
+
function it(n, g) {
|
|
2513
|
+
const te = Math.max(0, Re - 1);
|
|
2514
|
+
if (n = Math.max(0, Math.min(te, n)), g = Math.max(0, Math.min(te, g)), n > g) {
|
|
2515
|
+
const ie = n;
|
|
2516
|
+
n = g, g = ie;
|
|
2517
|
+
}
|
|
2518
|
+
M.current = n, y.current = g, U(n), re(g), mr();
|
|
2519
|
+
}
|
|
2520
|
+
function Rr(n) {
|
|
2521
|
+
const g = parseInt(n.target.value, 10);
|
|
2522
|
+
X ? it(g, g) : it(g, y.current);
|
|
2523
|
+
}
|
|
2524
|
+
function Tr(n) {
|
|
2525
|
+
const g = parseInt(n.target.value, 10);
|
|
2526
|
+
it(X ? g : M.current, g);
|
|
2527
|
+
}
|
|
2528
|
+
function wn() {
|
|
2529
|
+
const n = !X;
|
|
2530
|
+
ke(n), n && it(y.current, y.current);
|
|
2531
|
+
}
|
|
2532
|
+
function Or(n) {
|
|
2533
|
+
const g = n.target.value;
|
|
2534
|
+
xt(g), E.current = g, Ot();
|
|
2535
|
+
}
|
|
2536
|
+
Te(() => {
|
|
2537
|
+
var te, ie;
|
|
2538
|
+
if (!fe) return;
|
|
2539
|
+
const n = (ie = (te = $.current[ve.current]) == null ? void 0 : te.stats) == null ? void 0 : ie.filament_mm_by_tool;
|
|
2540
|
+
(Array.isArray(n) ? n.filter((Ne) => Ne > 0).length : 0) > 1 && E.current === "feature" && (xt("filament"), E.current = "filament", Ot());
|
|
2541
|
+
}, [fe]);
|
|
2542
|
+
function En(n) {
|
|
2543
|
+
const g = n.target.checked;
|
|
2544
|
+
Ye(g), S.current = g;
|
|
2545
|
+
for (const te of Object.values(ce.current)) te.ctl.setTravelVisible(g);
|
|
2546
|
+
}
|
|
2547
|
+
function Lr(n) {
|
|
2548
|
+
const g = n.target.checked;
|
|
2549
|
+
r((te) => ({ ...te, enable_support: g }));
|
|
2550
|
+
}
|
|
2551
|
+
const Sr = !!He(t, "enable_support"), Fr = (((zn = Un.support_style) == null ? void 0 : zn.enum_values) ?? []).map((n, g) => {
|
|
2552
|
+
var te, ie;
|
|
2553
|
+
return { value: n, label: ((ie = (te = Un.support_style) == null ? void 0 : te.enum_labels) == null ? void 0 : ie[g]) ?? n };
|
|
2554
|
+
}), Br = String(He(t, "support_style") ?? "default"), Dr = Number(He(t, "support_filament")) || 0, $r = Number(He(t, "support_interface_filament")) || 0, [Xt, Ir] = ae(!1), Yt = Number(He(t, "support_threshold_angle")) || 30;
|
|
2555
|
+
Te(() => {
|
|
2556
|
+
var n;
|
|
2557
|
+
(n = R.current) == null || n.setOverhang(Xt && be === "prepare" ? Yt : null);
|
|
2558
|
+
}, [Xt, Yt, be, d.length]);
|
|
2559
|
+
function Kt() {
|
|
2560
|
+
A(J.current.map((n) => ({ id: n.id, name: n.name, extruder: n.extruder, visible: n.visible !== !1 })));
|
|
2561
|
+
}
|
|
2562
|
+
function Zr(n, g) {
|
|
2563
|
+
_e((te) => {
|
|
2564
|
+
var Ne;
|
|
2565
|
+
const ie = [...te];
|
|
2566
|
+
return ie[n] = g, Le.current = ie, (Ne = R.current) == null || Ne.recolorObjects(), Ot(), ie;
|
|
1688
2567
|
});
|
|
1689
2568
|
}
|
|
1690
|
-
function
|
|
1691
|
-
|
|
1692
|
-
if (
|
|
1693
|
-
const
|
|
1694
|
-
return
|
|
2569
|
+
function Vr() {
|
|
2570
|
+
_e((n) => {
|
|
2571
|
+
if (n.length >= $t) return n;
|
|
2572
|
+
const g = [...n, Qn[n.length] || "#888888"];
|
|
2573
|
+
return Le.current = g, g;
|
|
1695
2574
|
});
|
|
1696
2575
|
}
|
|
1697
|
-
function
|
|
1698
|
-
|
|
1699
|
-
var
|
|
1700
|
-
if (
|
|
1701
|
-
const
|
|
1702
|
-
return
|
|
1703
|
-
var
|
|
1704
|
-
|
|
1705
|
-
|
|
2576
|
+
function Gr(n) {
|
|
2577
|
+
_e((g) => {
|
|
2578
|
+
var Ne;
|
|
2579
|
+
if (g.length <= 1) return g;
|
|
2580
|
+
const te = Number.isInteger(n) ? Math.min(Math.max(n, 0), g.length - 1) : g.length - 1, ie = g.filter((Be, De) => De !== te);
|
|
2581
|
+
return Le.current = ie, J.current.forEach((Be) => {
|
|
2582
|
+
var Ke, wt;
|
|
2583
|
+
const De = Be.extruder || 1;
|
|
2584
|
+
De === te + 1 ? (Ke = R.current) == null || Ke.setObjectExtruder(Be.id, 1) : De > te + 1 && ((wt = R.current) == null || wt.setObjectExtruder(Be.id, De - 1));
|
|
2585
|
+
}), (Ne = R.current) == null || Ne.recolorObjects(), Kt(), ie;
|
|
1706
2586
|
});
|
|
1707
2587
|
}
|
|
1708
|
-
function
|
|
1709
|
-
var
|
|
1710
|
-
const
|
|
1711
|
-
(
|
|
2588
|
+
function Ur(n) {
|
|
2589
|
+
var te;
|
|
2590
|
+
const g = J.current.find((ie) => ie.id === n);
|
|
2591
|
+
(te = R.current) == null || te.setObjectVisible(n, (g == null ? void 0 : g.visible) === !1), Kt();
|
|
1712
2592
|
}
|
|
1713
|
-
|
|
1714
|
-
|
|
2593
|
+
const kn = de === "enforcer" || de === "blocker";
|
|
2594
|
+
function _n() {
|
|
2595
|
+
nt(kn ? "off" : "enforcer");
|
|
1715
2596
|
}
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
2597
|
+
function Nn(n) {
|
|
2598
|
+
const g = Number.isInteger(n) ? n : null;
|
|
2599
|
+
f.current = g, st(g), V.current !== "material" && nt("material");
|
|
2600
|
+
}
|
|
2601
|
+
const Mn = we.map((n, g) => {
|
|
2602
|
+
const te = Ut[g + 1];
|
|
2603
|
+
return Number.isFinite(te) ? te : g === 0 ? Gt.enf : g === 1 ? Gt.blk : 0;
|
|
2604
|
+
}), {
|
|
2605
|
+
duplicateSelected: Jt,
|
|
2606
|
+
copySelected: An,
|
|
2607
|
+
pasteClipboard: Cn,
|
|
2608
|
+
deleteSelected: Qt,
|
|
2609
|
+
deleteAllObjects: Wr,
|
|
2610
|
+
splitSelected: en,
|
|
2611
|
+
setGizmo: Hr
|
|
2612
|
+
} = oo({
|
|
2613
|
+
apiRef: R,
|
|
2614
|
+
objectsRef: J,
|
|
2615
|
+
clipboardRef: w,
|
|
2616
|
+
paintModeRef: V,
|
|
2617
|
+
setPaintMode: nt,
|
|
2618
|
+
removeObject: vn,
|
|
2619
|
+
refreshObjects: Kt,
|
|
2620
|
+
setError: me,
|
|
2621
|
+
setSliceNotice: pt
|
|
2622
|
+
}), qr = qa({
|
|
1735
2623
|
add: () => {
|
|
1736
|
-
var
|
|
1737
|
-
return (
|
|
2624
|
+
var n;
|
|
2625
|
+
return (n = Ue.current) == null ? void 0 : n.click();
|
|
1738
2626
|
},
|
|
1739
|
-
remove:
|
|
1740
|
-
removeAll:
|
|
1741
|
-
duplicate:
|
|
1742
|
-
split:
|
|
2627
|
+
remove: Qt,
|
|
2628
|
+
removeAll: Wr,
|
|
2629
|
+
duplicate: Jt,
|
|
2630
|
+
split: en,
|
|
1743
2631
|
placeOnBed: () => {
|
|
1744
|
-
var
|
|
1745
|
-
return (
|
|
2632
|
+
var n;
|
|
2633
|
+
return (n = R.current) == null ? void 0 : n.placeOnBed();
|
|
1746
2634
|
},
|
|
1747
|
-
objectCount: () =>
|
|
2635
|
+
objectCount: () => d.length
|
|
1748
2636
|
});
|
|
1749
|
-
|
|
1750
|
-
slicing:
|
|
1751
|
-
isPreview: () =>
|
|
1752
|
-
slice:
|
|
1753
|
-
copy:
|
|
1754
|
-
paste:
|
|
1755
|
-
remove:
|
|
1756
|
-
duplicate:
|
|
1757
|
-
stepLayer: (
|
|
1758
|
-
const
|
|
1759
|
-
|
|
2637
|
+
pe.current = Xa({
|
|
2638
|
+
slicing: se,
|
|
2639
|
+
isPreview: () => v.current === "preview",
|
|
2640
|
+
slice: qt,
|
|
2641
|
+
copy: An,
|
|
2642
|
+
paste: Cn,
|
|
2643
|
+
remove: Qt,
|
|
2644
|
+
duplicate: Jt,
|
|
2645
|
+
stepLayer: (n) => {
|
|
2646
|
+
const g = y.current + n;
|
|
2647
|
+
it(X ? g : M.current, g);
|
|
1760
2648
|
},
|
|
1761
|
-
toggleSingleLayer:
|
|
1762
|
-
toggleTravel: () =>
|
|
2649
|
+
toggleSingleLayer: wn,
|
|
2650
|
+
toggleTravel: () => En({ target: { checked: !S.current } }),
|
|
1763
2651
|
zoomAll: () => {
|
|
1764
|
-
var
|
|
1765
|
-
return (
|
|
2652
|
+
var n;
|
|
2653
|
+
return (n = R.current) == null ? void 0 : n.frame();
|
|
1766
2654
|
},
|
|
1767
2655
|
zoomBed: () => {
|
|
1768
|
-
var
|
|
1769
|
-
return (
|
|
2656
|
+
var n;
|
|
2657
|
+
return (n = R.current) == null ? void 0 : n.frameBed();
|
|
1770
2658
|
},
|
|
1771
|
-
leavePreview: () =>
|
|
1772
|
-
setGizmo:
|
|
2659
|
+
leavePreview: () => Se("prepare"),
|
|
2660
|
+
setGizmo: Hr,
|
|
1773
2661
|
cancelTool: () => {
|
|
1774
|
-
var
|
|
1775
|
-
|
|
2662
|
+
var n;
|
|
2663
|
+
V.current !== "off" && nt("off"), (n = R.current) == null || n.detachTransform();
|
|
1776
2664
|
},
|
|
1777
|
-
rotateSelected: (
|
|
1778
|
-
var
|
|
1779
|
-
return (
|
|
2665
|
+
rotateSelected: (n) => {
|
|
2666
|
+
var g;
|
|
2667
|
+
return (g = R.current) == null ? void 0 : g.rotateSelectedY(n);
|
|
1780
2668
|
},
|
|
1781
|
-
nudgeSelected: (
|
|
1782
|
-
var
|
|
1783
|
-
return (
|
|
2669
|
+
nudgeSelected: (n, g) => {
|
|
2670
|
+
var te;
|
|
2671
|
+
return (te = R.current) == null ? void 0 : te.nudgeSelected(n, g);
|
|
1784
2672
|
},
|
|
1785
|
-
toggleHelp: () =>
|
|
2673
|
+
toggleHelp: () => ft((n) => !n)
|
|
1786
2674
|
});
|
|
1787
|
-
const
|
|
1788
|
-
(
|
|
1789
|
-
const
|
|
1790
|
-
|
|
2675
|
+
const Xr = Oe.nozzle_diameter || He(t, "nozzle_diameter") || "0.4";
|
|
2676
|
+
(Tn = (Rn = Tt.current).invalidate) == null || Tn.call(Rn);
|
|
2677
|
+
const jn = Re > 0 && /* @__PURE__ */ e.createElement(
|
|
2678
|
+
go,
|
|
2679
|
+
{
|
|
2680
|
+
viewType: yt,
|
|
2681
|
+
onViewType: Or,
|
|
2682
|
+
layerCount: Re,
|
|
2683
|
+
layerLo: l,
|
|
2684
|
+
layerHi: Y,
|
|
2685
|
+
segCount: dt,
|
|
2686
|
+
singleLayer: X,
|
|
2687
|
+
onLayerLo: Rr,
|
|
2688
|
+
onLayerHi: Tr,
|
|
2689
|
+
onToggleSingle: wn,
|
|
2690
|
+
showTravel: Qe,
|
|
2691
|
+
onToggleTravel: En,
|
|
2692
|
+
colorRange: jt,
|
|
2693
|
+
roleLegend: ze,
|
|
2694
|
+
extruderColors: we
|
|
2695
|
+
}
|
|
2696
|
+
), Ge = (On = $.current[ve.current]) == null ? void 0 : On.stats, Yr = fe && {
|
|
2697
|
+
...fe,
|
|
2698
|
+
filamentPerTool: Array.isArray(Ge == null ? void 0 : Ge.filament_mm_by_tool) ? Ge.filament_mm_by_tool : void 0,
|
|
2699
|
+
filamentPurge: Number.isFinite(Ge == null ? void 0 : Ge.filament_mm_purge) ? Ge.filament_mm_purge : void 0,
|
|
2700
|
+
filamentPurgePerTool: Array.isArray(Ge == null ? void 0 : Ge.filament_mm_purge_by_tool) ? Ge.filament_mm_purge_by_tool : void 0
|
|
2701
|
+
}, Pn = (n) => {
|
|
2702
|
+
const g = He(t, n);
|
|
2703
|
+
return Array.isArray(g) ? g : g ? [g] : [];
|
|
2704
|
+
}, ut = $.current[ve.current], Kr = ut != null && ut.stats && Number.isFinite(ut.stats.filament_mm_purge) ? {
|
|
2705
|
+
purge: ut.stats.filament_mm_purge,
|
|
2706
|
+
changes: (((Ln = ut.gcode) == null ? void 0 : Ln.match(/^T\d+$/gm)) ?? []).length,
|
|
2707
|
+
x: (Sn = window.__vpParams) == null ? void 0 : Sn.prime_tower_x,
|
|
2708
|
+
y: (Fn = window.__vpParams) == null ? void 0 : Fn.prime_tower_y
|
|
2709
|
+
} : null, Jr = /* @__PURE__ */ e.createElement(
|
|
2710
|
+
vo,
|
|
1791
2711
|
{
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
onToggleSingle: St,
|
|
1802
|
-
showTravel: Le,
|
|
1803
|
-
onToggleTravel: Rt,
|
|
1804
|
-
colorRange: nt,
|
|
1805
|
-
roleLegend: U
|
|
1806
|
-
}
|
|
1807
|
-
), Pn = /* @__PURE__ */ e.createElement(Fr, { stats: p, overBed: ue }), ht = bt.map((o) => o.toUpperCase()).join(" · ");
|
|
1808
|
-
return /* @__PURE__ */ e.createElement(Yn, { css: Jn }, /* @__PURE__ */ e.createElement("div", { className: "app-shell" }, /* @__PURE__ */ e.createElement("input", { ref: Ae, type: "file", accept: bt.map((o) => "." + o).join(","), multiple: !0, onChange: pn, title: `${ht} (multiple files allowed)`, "data-testid": "stl-input", style: { display: "none" } }), /* @__PURE__ */ e.createElement(
|
|
1809
|
-
zr,
|
|
2712
|
+
stats: Yr,
|
|
2713
|
+
overBed: Ae,
|
|
2714
|
+
extruderColors: we,
|
|
2715
|
+
filamentTypes: Pn("filament_type"),
|
|
2716
|
+
filamentIds: Pn("filament_settings_id")
|
|
2717
|
+
}
|
|
2718
|
+
), tn = an.map((n) => n.toUpperCase()).join(" · ");
|
|
2719
|
+
return /* @__PURE__ */ e.createElement(_a, { css: Na }, /* @__PURE__ */ e.createElement("div", { className: "app-shell" }, /* @__PURE__ */ e.createElement("input", { ref: Ue, type: "file", accept: an.map((n) => "." + n).join(","), multiple: !0, onChange: Mr, title: `${tn} (multiple files allowed)`, "data-testid": "stl-input", style: { display: "none" } }), m("topBar") && /* @__PURE__ */ e.createElement(
|
|
2720
|
+
lo,
|
|
1810
2721
|
{
|
|
1811
|
-
showTabs:
|
|
1812
|
-
canvasMode:
|
|
1813
|
-
onCanvasMode:
|
|
1814
|
-
previewEnabled:
|
|
2722
|
+
showTabs: Ee,
|
|
2723
|
+
canvasMode: be,
|
|
2724
|
+
onCanvasMode: Se,
|
|
2725
|
+
previewEnabled: Re > 0,
|
|
1815
2726
|
onOpen: () => {
|
|
1816
|
-
var
|
|
1817
|
-
return (
|
|
2727
|
+
var n;
|
|
2728
|
+
return (n = Ue.current) == null ? void 0 : n.click();
|
|
1818
2729
|
}
|
|
1819
2730
|
}
|
|
1820
|
-
), /* @__PURE__ */ e.createElement("div", { className: "app-body" },
|
|
1821
|
-
|
|
2731
|
+
), /* @__PURE__ */ e.createElement("div", { className: "app-body" }, Ee && be === "prepare" && m("gizmoRail") && /* @__PURE__ */ e.createElement(
|
|
2732
|
+
so,
|
|
1822
2733
|
{
|
|
1823
|
-
gizmoMode:
|
|
1824
|
-
paintMode:
|
|
1825
|
-
onGizmo: (
|
|
1826
|
-
var
|
|
1827
|
-
|
|
2734
|
+
gizmoMode: k,
|
|
2735
|
+
paintMode: de,
|
|
2736
|
+
onGizmo: (n) => {
|
|
2737
|
+
var g;
|
|
2738
|
+
nt("off"), (g = R.current) == null || g.setMode(n);
|
|
1828
2739
|
},
|
|
1829
|
-
onTogglePaint:
|
|
2740
|
+
onTogglePaint: _n
|
|
1830
2741
|
}
|
|
1831
2742
|
), /* @__PURE__ */ e.createElement("div", { className: "viewport-col" }, /* @__PURE__ */ e.createElement(
|
|
1832
2743
|
"div",
|
|
1833
2744
|
{
|
|
1834
|
-
className: (
|
|
1835
|
-
ref:
|
|
1836
|
-
onDrop:
|
|
1837
|
-
onDragOver:
|
|
1838
|
-
onDragLeave:
|
|
2745
|
+
className: (Ee ? "vp-canvas" : "vp-canvas fail") + (Ve ? " drag-over" : ""),
|
|
2746
|
+
ref: sr,
|
|
2747
|
+
onDrop: Ar,
|
|
2748
|
+
onDragOver: Cr,
|
|
2749
|
+
onDragLeave: jr,
|
|
1839
2750
|
"data-testid": "drop-zone"
|
|
1840
2751
|
},
|
|
1841
|
-
!
|
|
1842
|
-
|
|
1843
|
-
var
|
|
1844
|
-
return (
|
|
1845
|
-
}, "data-testid": "empty-pick", title: `Pick a ${
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
2752
|
+
!Ee && /* @__PURE__ */ e.createElement("div", { className: "vp-fallback" }, "⚠ ", q),
|
|
2753
|
+
Ee && d.length === 0 && be !== "preview" && m("emptyHint") && /* @__PURE__ */ e.createElement("div", { className: "empty-hint", "data-testid": "empty-hint" }, /* @__PURE__ */ e.createElement("div", { className: "eh-icon" }, "📦"), /* @__PURE__ */ e.createElement("div", { className: "eh-title" }, "Drag in a file or pick one"), /* @__PURE__ */ e.createElement("div", { className: "eh-sub" }, tn), /* @__PURE__ */ e.createElement("button", { className: "eh-btn", onClick: () => {
|
|
2754
|
+
var n;
|
|
2755
|
+
return (n = Ue.current) == null ? void 0 : n.click();
|
|
2756
|
+
}, "data-testid": "empty-pick", title: `Pick a ${tn} file (multiple allowed)` }, "Choose file")),
|
|
2757
|
+
Ve && /* @__PURE__ */ e.createElement("div", { className: "drop-overlay", "data-testid": "drop-overlay" }, "Drop here (STL/OBJ/3MF/AMF/PLY)"),
|
|
2758
|
+
bt && /* @__PURE__ */ e.createElement(
|
|
2759
|
+
co,
|
|
1849
2760
|
{
|
|
1850
|
-
menu:
|
|
1851
|
-
onClose: () =>
|
|
1852
|
-
canPaste: !!
|
|
2761
|
+
menu: bt,
|
|
2762
|
+
onClose: () => gt(null),
|
|
2763
|
+
canPaste: !!w.current,
|
|
1853
2764
|
actions: {
|
|
1854
|
-
duplicate:
|
|
1855
|
-
copy:
|
|
1856
|
-
split:
|
|
2765
|
+
duplicate: Jt,
|
|
2766
|
+
copy: An,
|
|
2767
|
+
split: en,
|
|
1857
2768
|
placeOnBed: () => {
|
|
1858
|
-
var
|
|
1859
|
-
return (
|
|
2769
|
+
var n;
|
|
2770
|
+
return (n = R.current) == null ? void 0 : n.placeOnBed();
|
|
1860
2771
|
},
|
|
1861
|
-
remove:
|
|
2772
|
+
remove: Qt,
|
|
1862
2773
|
openFile: () => {
|
|
1863
|
-
var
|
|
1864
|
-
return (
|
|
2774
|
+
var n;
|
|
2775
|
+
return (n = Ue.current) == null ? void 0 : n.click();
|
|
1865
2776
|
},
|
|
1866
|
-
paste:
|
|
2777
|
+
paste: Cn,
|
|
1867
2778
|
zoomAll: () => {
|
|
1868
|
-
var
|
|
1869
|
-
return (
|
|
2779
|
+
var n;
|
|
2780
|
+
return (n = R.current) == null ? void 0 : n.frame();
|
|
1870
2781
|
},
|
|
1871
2782
|
zoomBed: () => {
|
|
1872
|
-
var
|
|
1873
|
-
return (
|
|
2783
|
+
var n;
|
|
2784
|
+
return (n = R.current) == null ? void 0 : n.frameBed();
|
|
1874
2785
|
}
|
|
1875
2786
|
}
|
|
1876
2787
|
}
|
|
1877
2788
|
),
|
|
1878
|
-
|
|
1879
|
-
),
|
|
1880
|
-
|
|
2789
|
+
mt && /* @__PURE__ */ e.createElement(po, { onClose: () => ft(!1) })
|
|
2790
|
+
), Ee && be === "prepare" && m("objectToolbar") && /* @__PURE__ */ e.createElement(io, { tools: qr }), Ee && be === "prepare" && kn && m("paintPanel") && /* @__PURE__ */ e.createElement(
|
|
2791
|
+
ho,
|
|
1881
2792
|
{
|
|
1882
|
-
paintMode:
|
|
1883
|
-
onPaintMode:
|
|
1884
|
-
onClear:
|
|
1885
|
-
brushRadius:
|
|
1886
|
-
paintCounts:
|
|
1887
|
-
|
|
1888
|
-
|
|
2793
|
+
paintMode: de,
|
|
2794
|
+
onPaintMode: nt,
|
|
2795
|
+
onClear: yn,
|
|
2796
|
+
brushRadius: tt,
|
|
2797
|
+
paintCounts: Gt,
|
|
2798
|
+
paintTool: Pt,
|
|
2799
|
+
onPaintTool: sn,
|
|
2800
|
+
brushCursor: zt,
|
|
2801
|
+
onBrushCursor: cn,
|
|
2802
|
+
fillAngle: Rt,
|
|
2803
|
+
onFillAngle: dn,
|
|
2804
|
+
onBrushRadius: (n) => {
|
|
2805
|
+
Vt(n), N.current = n;
|
|
1889
2806
|
}
|
|
1890
2807
|
}
|
|
1891
|
-
),
|
|
1892
|
-
|
|
2808
|
+
), Ee && be === "prepare" && de === "material" && m("paintPanel") && /* @__PURE__ */ e.createElement(
|
|
2809
|
+
fo,
|
|
1893
2810
|
{
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
2811
|
+
colors: we,
|
|
2812
|
+
activeExtruder: Zt,
|
|
2813
|
+
onSelectExtruder: Nn,
|
|
2814
|
+
onClear: yn,
|
|
2815
|
+
onClose: () => nt("off"),
|
|
2816
|
+
brushRadius: tt,
|
|
2817
|
+
paintCounts: Mn,
|
|
2818
|
+
paintTool: Pt,
|
|
2819
|
+
onPaintTool: sn,
|
|
2820
|
+
brushCursor: zt,
|
|
2821
|
+
onBrushCursor: cn,
|
|
2822
|
+
fillAngle: Rt,
|
|
2823
|
+
onFillAngle: dn,
|
|
2824
|
+
onBrushRadius: (n) => {
|
|
2825
|
+
Vt(n), N.current = n;
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
), Ee && be === "preview" && fe && m("statsCard") && /* @__PURE__ */ e.createElement("div", { className: "stats-card", "data-testid": "slice-stats" }, Jr), Ee && m("plateBar") && /* @__PURE__ */ e.createElement(
|
|
2829
|
+
bo,
|
|
1903
2830
|
{
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
$r,
|
|
2831
|
+
plateCount: Je,
|
|
2832
|
+
selectedPlate: $e,
|
|
2833
|
+
maxPlates: tr,
|
|
2834
|
+
onSelect: Nr,
|
|
2835
|
+
onAdd: kr,
|
|
2836
|
+
onDelete: _r
|
|
2837
|
+
}
|
|
2838
|
+
), Ee && m("status") && /* @__PURE__ */ e.createElement("div", { className: "vp-status", "data-testid": "vp-status" }, q)), Ee && m("sidebar") && /* @__PURE__ */ e.createElement("aside", { className: "sidebar" }, /* @__PURE__ */ e.createElement("div", { className: "sidebar-scroll" }, m("printerCard") && /* @__PURE__ */ e.createElement(
|
|
2839
|
+
wo,
|
|
1914
2840
|
{
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
2841
|
+
bedWidth: Oe.bed_width,
|
|
2842
|
+
bedDepth: Oe.bed_depth,
|
|
2843
|
+
nozzleDia: Xr,
|
|
2844
|
+
onBedSize: Pr,
|
|
2845
|
+
settings: t,
|
|
2846
|
+
setSettings: r,
|
|
2847
|
+
motionPanel: i
|
|
2848
|
+
}
|
|
2849
|
+
), m("filamentCard") && /* @__PURE__ */ e.createElement(
|
|
2850
|
+
Eo,
|
|
2851
|
+
{
|
|
2852
|
+
colors: we,
|
|
2853
|
+
onColor: Zr,
|
|
2854
|
+
onAdd: Vr,
|
|
2855
|
+
onRemove: Gr,
|
|
2856
|
+
settings: t,
|
|
2857
|
+
setSettings: r,
|
|
2858
|
+
filamentPanel: o,
|
|
2859
|
+
paintMode: de,
|
|
2860
|
+
onPaintExtruder: Nn,
|
|
2861
|
+
paintCounts: Mn
|
|
2862
|
+
}
|
|
2863
|
+
), d.length > 0 && m("objectList") && /* @__PURE__ */ e.createElement(
|
|
2864
|
+
ko,
|
|
2865
|
+
{
|
|
2866
|
+
objects: d,
|
|
2867
|
+
extruderColors: we,
|
|
2868
|
+
onToggleVisible: Ur,
|
|
2869
|
+
onExtruder: zr,
|
|
2870
|
+
onSplit: (n) => {
|
|
2871
|
+
var g;
|
|
2872
|
+
(g = R.current) == null || g.selectObject(n), en();
|
|
1922
2873
|
},
|
|
1923
|
-
onRemove:
|
|
1924
|
-
supportOn:
|
|
1925
|
-
onToggleSupport:
|
|
1926
|
-
overhangOn:
|
|
1927
|
-
onToggleOverhang: (
|
|
1928
|
-
overhangAngle:
|
|
1929
|
-
paintMode:
|
|
1930
|
-
onTogglePaint:
|
|
1931
|
-
supportStyle:
|
|
1932
|
-
supportStyles:
|
|
1933
|
-
onSupportStyle: (
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
2874
|
+
onRemove: vn,
|
|
2875
|
+
supportOn: Sr,
|
|
2876
|
+
onToggleSupport: Lr,
|
|
2877
|
+
overhangOn: Xt,
|
|
2878
|
+
onToggleOverhang: (n) => Ir(n.target.checked),
|
|
2879
|
+
overhangAngle: Yt,
|
|
2880
|
+
paintMode: de,
|
|
2881
|
+
onTogglePaint: _n,
|
|
2882
|
+
supportStyle: Br,
|
|
2883
|
+
supportStyles: Fr,
|
|
2884
|
+
onSupportStyle: (n) => r((g) => ({ ...g, support_style: n })),
|
|
2885
|
+
supportFilament: Dr,
|
|
2886
|
+
onSupportFilament: (n) => r((g) => ({ ...g, support_filament: n })),
|
|
2887
|
+
supportInterfaceFilament: $r,
|
|
2888
|
+
onSupportInterfaceFilament: (n) => r((g) => ({ ...g, support_interface_filament: n }))
|
|
2889
|
+
}
|
|
2890
|
+
), we.length > 1 && m("towerCard") && /* @__PURE__ */ e.createElement(
|
|
2891
|
+
No,
|
|
2892
|
+
{
|
|
2893
|
+
settings: t,
|
|
2894
|
+
setSettings: r,
|
|
2895
|
+
extruderColors: we,
|
|
2896
|
+
wipeTowerReal: et,
|
|
2897
|
+
onToggleWipeTower: (n) => vt(n.target.checked),
|
|
2898
|
+
towerStats: Kr
|
|
2899
|
+
}
|
|
2900
|
+
), u && /* @__PURE__ */ e.createElement("div", { className: "slice-warn side-warn" }, "⚠ ", u), Wt && /* @__PURE__ */ e.createElement("div", { className: "slice-warn side-warn", "data-testid": "slice-notice" }, "ℹ ", Wt), he && /* @__PURE__ */ e.createElement("div", { className: "slice-err side-warn", "data-testid": "slice-err" }, he), fn && /* @__PURE__ */ e.createElement("button", { className: "slice-btn", "data-testid": "downgrade-retry", onClick: Er, title: "Simplify the infill and lower its density to reduce memory pressure, then retry" }, "Simplified retry (simple infill, economy mode)"), be === "preview" && jn && m("previewControls") && /* @__PURE__ */ e.createElement("section", { className: "side-card" }, /* @__PURE__ */ e.createElement("div", { className: "sc-head" }, "🎚 Preview"), jn), m("processCard") && /* @__PURE__ */ e.createElement("section", { className: "side-card process-card", "data-testid": "process-section" }, /* @__PURE__ */ e.createElement("div", { className: "sc-head" }, "⚙ Process"), c)), m("sliceBar") && /* @__PURE__ */ e.createElement(
|
|
2901
|
+
Mo,
|
|
1939
2902
|
{
|
|
1940
|
-
autoSlice:
|
|
1941
|
-
onAutoSlice:
|
|
1942
|
-
slicing:
|
|
1943
|
-
progress:
|
|
1944
|
-
plateCount:
|
|
1945
|
-
selectedPlate:
|
|
1946
|
-
sliceMenuOpen:
|
|
1947
|
-
onSliceMenu: () =>
|
|
1948
|
-
slicedPlateCount:
|
|
1949
|
-
canSlice:
|
|
1950
|
-
onSlice:
|
|
1951
|
-
onCancel:
|
|
1952
|
-
onExportAll:
|
|
1953
|
-
gcodeUrl:
|
|
2903
|
+
autoSlice: xe,
|
|
2904
|
+
onAutoSlice: je,
|
|
2905
|
+
slicing: se,
|
|
2906
|
+
progress: Z,
|
|
2907
|
+
plateCount: Je,
|
|
2908
|
+
selectedPlate: $e,
|
|
2909
|
+
sliceMenuOpen: At,
|
|
2910
|
+
onSliceMenu: () => Ct((n) => !n),
|
|
2911
|
+
slicedPlateCount: at,
|
|
2912
|
+
canSlice: d.length > 0,
|
|
2913
|
+
onSlice: qt,
|
|
2914
|
+
onCancel: gn,
|
|
2915
|
+
onExportAll: wr,
|
|
2916
|
+
gcodeUrl: Ie
|
|
1954
2917
|
}
|
|
1955
2918
|
)))));
|
|
1956
2919
|
}
|
|
1957
2920
|
export {
|
|
1958
|
-
|
|
2921
|
+
Fo as default
|
|
1959
2922
|
};
|