three-slicer 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +342 -24
- package/components/README.md +1 -1
- package/components/dist/SettingsPanel.js +111 -112
- package/components/styles.css +9 -9
- package/data/invalidation-map.json +1 -1
- package/engine/examples/headless.mjs +2 -2
- package/engine/index.d.ts +3 -1
- package/engine/index.js +2 -2
- package/engine/src/data.js +12 -0
- package/engine/src/settings.js +35 -35
- package/engine/src/slicer.worker.js +25 -22
- package/engine/src/slicer_core.js +0 -0
- package/engine/src/slicer_core.mt.js +0 -0
- package/engine/src/toggle_eval.js +12 -13
- package/package.json +54 -26
- package/types/components.d.ts +19 -0
- package/types/data/config-schema.json.d.ts +55 -0
- package/types/data/invalidation-map.json.d.ts +15 -0
- package/types/data/toggle-rules.json.d.ts +20 -0
- package/types/data/ui-tree.json.d.ts +19 -0
- package/types/data.d.ts +17 -0
- package/types/gen_settings_types.mjs +70 -0
- package/types/settings-keys.d.ts +1704 -0
- package/types/settings.d.ts +19 -0
- package/types/toggle.d.ts +22 -0
- package/types/viewer-loaders.d.ts +33 -0
- package/types/viewer-toolpath.d.ts +105 -0
- package/types/viewer.d.ts +15 -0
- package/types/wasm.d.ts +5 -0
- package/types/worker.d.ts +3 -0
- package/viewer/README.md +1 -1
- package/viewer/dist/Viewport.js +1774 -923
- package/viewer/dist/make_worker.js +6 -6
- package/viewer/dist/model_loaders.js +221 -109
- package/viewer/dist/toolpath_gpu.js +146 -147
- package/viewer/styles.css +27 -25
- package/data/config-schema-builddump.json +0 -12921
- package/viewer/src/Viewport.jsx +0 -1353
- package/viewer/src/assets/add.svg +0 -1
- package/viewer/src/assets/arrange.svg +0 -1
- package/viewer/src/assets/boolean.svg +0 -1
- package/viewer/src/assets/cut.svg +0 -1
- package/viewer/src/assets/delete.svg +0 -1
- package/viewer/src/assets/deleteall.svg +0 -1
- package/viewer/src/assets/duplicate.svg +0 -1
- package/viewer/src/assets/measure.svg +0 -1
- package/viewer/src/assets/mmu.svg +0 -1
- package/viewer/src/assets/move.svg +0 -1
- package/viewer/src/assets/negative.svg +0 -1
- package/viewer/src/assets/onbed.svg +0 -1
- package/viewer/src/assets/open.svg +0 -1
- package/viewer/src/assets/orient.svg +0 -1
- package/viewer/src/assets/paint.svg +0 -1
- package/viewer/src/assets/rotate.svg +0 -1
- package/viewer/src/assets/scale.svg +0 -1
- package/viewer/src/assets/seam.svg +0 -1
- package/viewer/src/assets/split.svg +0 -1
- package/viewer/src/assets/textmark.svg +0 -1
- package/viewer/src/assets/varlayer.svg +0 -1
- package/viewer/src/icons.js +0 -23
- package/viewer/src/make_worker.js +0 -9
- package/viewer/src/model_loaders.js +0 -178
- package/viewer/src/shadow_host.jsx +0 -30
- package/viewer/src/toolpath_gpu.js +0 -430
package/viewer/dist/Viewport.js
CHANGED
|
@@ -1,1108 +1,1959 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
import e, { useRef as H, useState as $, useLayoutEffect as Ln, useEffect as Ve, useMemo as Tt } from "react";
|
|
2
|
+
import { deriveKernelParams as xt, settingRaw as Je, printersByVendor as On, processPresets as Tn, printerDefaultPreset as Bn, printerKeys as lt, machineLimitKeys as Dn, printerSettings as Zn } from "three-slicer/settings";
|
|
3
|
+
import { schema as Bt } from "three-slicer/data";
|
|
4
|
+
import { createPortal as In } from "react-dom";
|
|
5
|
+
import { SUPPORTED_EXT as bt, fileExt as Vn, loadModel as Fn, splitConnectedComponents as Gn } from "./model_loaders.js";
|
|
6
|
+
import * as N from "three";
|
|
7
|
+
import { OrbitControls as Un } from "three/examples/jsm/controls/OrbitControls.js";
|
|
8
|
+
import { TransformControls as $n } from "three/examples/jsm/controls/TransformControls.js";
|
|
9
|
+
import { makeSlicerWorker as Hn } from "./make_worker.js";
|
|
10
|
+
import { roleRatios as It, computeColors as Dt, buildSegmentData as qn, makeToolpath as Wn, VIEW_TYPES as Xn, DEFAULT_RANGES_COLORS as Kn } from "./toolpath_gpu.js";
|
|
11
|
+
function Yn({ css: n, className: a, children: c }) {
|
|
12
|
+
const l = H(null), [r] = $(() => {
|
|
13
|
+
const m = document.createElement("div");
|
|
14
|
+
return m.style.display = "contents", m;
|
|
14
15
|
});
|
|
15
|
-
return
|
|
16
|
-
const
|
|
17
|
-
let w =
|
|
18
|
-
w || (w = document.createElement("style"), w.setAttribute("data-ts-css", ""),
|
|
19
|
-
}, [
|
|
16
|
+
return Ln(() => {
|
|
17
|
+
const m = l.current, d = m.shadowRoot || m.attachShadow({ mode: "open" });
|
|
18
|
+
let w = d.querySelector("style[data-ts-css]");
|
|
19
|
+
w || (w = document.createElement("style"), w.setAttribute("data-ts-css", ""), d.append(w)), w.textContent = n, d.contains(r) || d.append(r);
|
|
20
|
+
}, [n, r]), /* @__PURE__ */ e.createElement("div", { ref: l, className: a }, In(c, r));
|
|
20
21
|
}
|
|
21
|
-
const ia = ":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}.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}.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}", ca = "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>'), da = "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>'), 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="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>'), 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="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>'), ma = "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>'), fa = "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>'), 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="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>'), 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="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>'), ga = "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>'), xa = "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>'), va = "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>'), 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="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>'), ya = "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>'), ka = "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>'), Ea = "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>'), Ma = "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>'), 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="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>'), 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="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>'), $n = "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>'), Na = "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>'), _a = "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>');
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
for (let y = 0; y < $; y += 3)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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 a = Math.sqrt(n), c = Math.round(a);
|
|
24
|
+
return a > c ? c + 1 : c;
|
|
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 wr(n) {
|
|
27
|
+
return [
|
|
28
|
+
{ id: "add", icon: er, label: "Add", tip: "Add a model file to the current plate (existing objects are kept)", run: n.add },
|
|
29
|
+
{ id: "delete", icon: Ft, label: "Delete", tip: "Delete the selected object (Del)", run: n.remove },
|
|
30
|
+
{ id: "delete-all", icon: or, label: "Delete all", tip: "Delete every object on the plate", run: n.removeAll, disabled: () => n.objectCount() === 0 },
|
|
31
|
+
{ sep: !0 },
|
|
32
|
+
{ id: "duplicate", icon: ar, label: "Duplicate", tip: "Duplicate the selected object (Ctrl+K)", run: n.duplicate },
|
|
33
|
+
{ id: "split", icon: Gt, 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: n.split },
|
|
34
|
+
{ id: "onbed", icon: ur, label: "Place on bed", tip: "Drop every object onto the bed (Z=0) — to re-seat after lifting with the gizmo", run: n.placeOnBed },
|
|
35
|
+
{ sep: !0 },
|
|
36
|
+
{ id: "arrange", icon: tr, label: "Arrange", tip: "Auto arrange — lay objects out on the bed without overlap. Not implemented (needs the libslic3r Arrange port)" },
|
|
37
|
+
{ id: "orient", icon: fr, label: "Orient", tip: "Auto orient — rotate to the orientation needing the least support. Not implemented (needs the libslic3r Orient port)" },
|
|
38
|
+
{ sep: !0 },
|
|
39
|
+
{ id: "cut", icon: rr, label: "Cut", tip: "Cut — slice the model with a plane into two pieces. Not implemented (needs cut-surface re-stitching)" },
|
|
40
|
+
{ id: "boolean", icon: nr, label: "Boolean", tip: "Mesh boolean — union/difference/intersection of two objects. Not implemented (needs the CGAL boolean port)" },
|
|
41
|
+
{ id: "negative", icon: pr, label: "Negative part", tip: "Add a negative/modifier part — put a part with different properties inside one object. Not implemented (no part concept)" },
|
|
42
|
+
{ sep: !0 },
|
|
43
|
+
{ id: "seam", icon: xr, label: "Seam painting", tip: "Seam painting — brush where the layer seam goes. Not implemented (needs kernel seam wiring)" },
|
|
44
|
+
{ id: "mmu", icon: cr, label: "Color painting", tip: "Color painting — assign multi-material colors per facet. Not implemented (needs the MMU paint codec wiring)" },
|
|
45
|
+
{ id: "text", icon: yr, label: "Text", tip: "Text/SVG emboss — engrave letters or shapes onto the model surface. Not implemented (needs font rasterization)" },
|
|
46
|
+
{ id: "measure", icon: ir, label: "Measure", tip: "Measure — distance and angle between two points or faces. Not implemented" },
|
|
47
|
+
{ id: "varlayer", icon: vr, label: "Variable layers", tip: "Variable layer height — different layer heights per band. Not implemented (the kernel has no variable z)" }
|
|
48
|
+
];
|
|
33
49
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
50
|
+
function kr(n) {
|
|
51
|
+
return (a) => {
|
|
52
|
+
var w;
|
|
53
|
+
const c = a.composedPath ? a.composedPath()[0] : a.target;
|
|
54
|
+
if (c && (c.tagName === "INPUT" || c.tagName === "TEXTAREA" || c.tagName === "SELECT" || c.isContentEditable)) return;
|
|
55
|
+
const l = a.key, r = typeof l == "string" ? l.toLowerCase() : "", m = a.ctrlKey || a.metaKey, d = () => {
|
|
56
|
+
a.preventDefault(), a.stopPropagation();
|
|
57
|
+
};
|
|
58
|
+
if (m) {
|
|
59
|
+
r === "r" ? (d(), n.slicing || n.slice("current")) : r === "c" ? (d(), n.copy()) : r === "v" ? (d(), n.paste()) : r === "x" ? (d(), n.copy(), n.remove()) : (r === "k" || r === "d") && (d(), n.duplicate());
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (n.isPreview()) {
|
|
63
|
+
const b = a.shiftKey ? 10 : 1;
|
|
64
|
+
l === "ArrowUp" ? (d(), n.stepLayer(b)) : l === "ArrowDown" ? (d(), n.stepLayer(-b)) : r === "l" ? (d(), n.toggleSingleLayer()) : r === "t" ? (d(), n.toggleTravel()) : r === "z" ? (d(), n.zoomAll()) : r === "b" ? (d(), n.zoomBed()) : l === "Escape" && (d(), n.leavePreview());
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (r === "m" || r === "g")
|
|
68
|
+
d(), n.setGizmo("translate");
|
|
69
|
+
else if (r === "r")
|
|
70
|
+
d(), n.setGizmo("rotate");
|
|
71
|
+
else if (r === "s")
|
|
72
|
+
d(), n.setGizmo("scale");
|
|
73
|
+
else if (r === "z")
|
|
74
|
+
d(), n.zoomAll();
|
|
75
|
+
else if (r === "b")
|
|
76
|
+
d(), n.zoomBed();
|
|
77
|
+
else if (l === "Delete" || l === "Backspace")
|
|
78
|
+
d(), n.remove();
|
|
79
|
+
else if (l === "Escape")
|
|
80
|
+
d(), n.cancelTool();
|
|
81
|
+
else if (l === "PageUp")
|
|
82
|
+
d(), n.rotateSelected(Math.PI / 4);
|
|
83
|
+
else if (l === "PageDown")
|
|
84
|
+
d(), n.rotateSelected(-Math.PI / 4);
|
|
85
|
+
else if ((w = l.startsWith) != null && w.call(l, "Arrow")) {
|
|
86
|
+
d();
|
|
87
|
+
const b = a.shiftKey ? 1 : 10;
|
|
88
|
+
n.nudgeSelected(
|
|
89
|
+
l === "ArrowLeft" ? -b : l === "ArrowRight" ? b : 0,
|
|
90
|
+
l === "ArrowUp" ? -b : l === "ArrowDown" ? b : 0
|
|
91
|
+
);
|
|
92
|
+
} else l === "?" && (d(), n.toggleHelp());
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function Er(n, a) {
|
|
96
|
+
const c = n.geometry, l = c == null ? void 0 : c.getAttribute("position");
|
|
97
|
+
if (!l) return null;
|
|
98
|
+
const r = c.getIndex(), m = (r ? r.count : l.count) / 3, d = Math.cos(Math.max(0, Math.min(90, a)) * Math.PI / 180), w = new N.Matrix3().getNormalMatrix(n.matrixWorld), b = new N.Vector3(), T = new N.Vector3(), P = new N.Vector3(), M = new N.Vector3(), B = new N.Vector3(), ee = new N.Vector3(), L = [];
|
|
99
|
+
for (let I = 0; I < m; I++) {
|
|
100
|
+
const A = r ? r.getX(I * 3) : I * 3, u = r ? r.getX(I * 3 + 1) : I * 3 + 1, _ = r ? r.getX(I * 3 + 2) : I * 3 + 2;
|
|
101
|
+
b.fromBufferAttribute(l, A), T.fromBufferAttribute(l, u), P.fromBufferAttribute(l, _), ee.copy(M.subVectors(T, b)).cross(B.subVectors(P, b)), ee.lengthSq() !== 0 && (ee.applyMatrix3(w).normalize(), !(-ee.y <= d) && L.push(b.x, b.y, b.z, T.x, T.y, T.z, P.x, P.y, P.z));
|
|
45
102
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
103
|
+
if (!L.length) return null;
|
|
104
|
+
const te = new N.BufferGeometry();
|
|
105
|
+
return te.setAttribute("position", new N.Float32BufferAttribute(L, 3)), te.computeVertexNormals(), te;
|
|
106
|
+
}
|
|
107
|
+
function Mr(n) {
|
|
108
|
+
const a = n.length, c = new Float32Array(a);
|
|
109
|
+
for (let M = 0; M < a; M += 3)
|
|
110
|
+
c[M] = n[M], c[M + 1] = n[M + 2], c[M + 2] = -n[M + 1];
|
|
111
|
+
let l = 1 / 0, r = 1 / 0, m = 1 / 0, d = -1 / 0, w = -1 / 0, b = -1 / 0;
|
|
112
|
+
for (let M = 0; M < a; M += 3)
|
|
113
|
+
l = Math.min(l, c[M]), d = Math.max(d, c[M]), r = Math.min(r, c[M + 1]), w = Math.max(w, c[M + 1]), m = Math.min(m, c[M + 2]), b = Math.max(b, c[M + 2]);
|
|
114
|
+
const T = (l + d) / 2, P = (m + b) / 2;
|
|
115
|
+
for (let M = 0; M < a; M += 3)
|
|
116
|
+
c[M] -= T, c[M + 1] -= r, c[M + 2] -= P;
|
|
117
|
+
return { localPos: c, size: { w: d - l, d: b - m, h: w - r } };
|
|
118
|
+
}
|
|
119
|
+
function jr(n) {
|
|
120
|
+
const {
|
|
121
|
+
apiRef: a,
|
|
122
|
+
objectsRef: c,
|
|
123
|
+
keyRef: l,
|
|
124
|
+
workerRef: r,
|
|
125
|
+
selectedPlateRef: m,
|
|
126
|
+
placeXRef: d,
|
|
127
|
+
plateCountRef: w,
|
|
128
|
+
canvasModeRef: b,
|
|
129
|
+
paintModeRef: T,
|
|
130
|
+
brushRadiusRef: P,
|
|
131
|
+
paintXformRef: M,
|
|
132
|
+
extruderColorsRef: B,
|
|
133
|
+
setOk: ee,
|
|
134
|
+
setStatus: L,
|
|
135
|
+
setGmode: te,
|
|
136
|
+
setCtxMenu: I,
|
|
137
|
+
setBrushRadius: A
|
|
138
|
+
} = n, u = H(null), _ = H({}), G = H(!1), K = H(200), h = H(200);
|
|
139
|
+
function E(j) {
|
|
140
|
+
const f = gt(w.current);
|
|
141
|
+
return { x: j % f * Ye(K.current), z: Math.floor(j / f) * Ye(h.current) };
|
|
49
142
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
143
|
+
function k(j, f) {
|
|
144
|
+
const g = w.current, y = gt(g), v = Math.max(0, Math.min(y - 1, Math.round(j / Ye(K.current)))), D = Math.max(0, Math.round(f / Ye(h.current)));
|
|
145
|
+
return Math.max(0, Math.min(g - 1, D * y + v));
|
|
146
|
+
}
|
|
147
|
+
return Ve(() => {
|
|
148
|
+
const j = u.current;
|
|
149
|
+
if (!j) return;
|
|
150
|
+
const f = document.createElement("canvas");
|
|
151
|
+
if (!(f.getContext("webgl2") || f.getContext("webgl"))) {
|
|
152
|
+
ee(!1), L("Cannot create a WebGL context in this environment (headless / no GPU).");
|
|
57
153
|
return;
|
|
58
154
|
}
|
|
59
|
-
let
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
if (!
|
|
76
|
-
|
|
77
|
-
const
|
|
78
|
-
Number.isFinite(
|
|
155
|
+
let g = j.clientWidth || 800, y = j.clientHeight || 480;
|
|
156
|
+
const v = new N.WebGLRenderer({ antialias: !0 });
|
|
157
|
+
v.setPixelRatio(Math.min(window.devicePixelRatio, 2)), v.setSize(g, y), v.setClearColor(1448478, 1), v.domElement.setAttribute("data-webgl", v.getContext() ? "ok" : "fail"), j.appendChild(v.domElement);
|
|
158
|
+
const D = new N.Scene(), W = new N.PerspectiveCamera(50, g / y, 1, 3e3);
|
|
159
|
+
W.position.set(210, 180, 260), D.add(new N.HemisphereLight(16777215, 2764598, 1));
|
|
160
|
+
const oe = new N.DirectionalLight(16777215, 1.1);
|
|
161
|
+
oe.position.set(120, 220, 160), D.add(oe);
|
|
162
|
+
const ge = new N.Group();
|
|
163
|
+
D.add(ge);
|
|
164
|
+
const de = new N.Group();
|
|
165
|
+
D.add(de);
|
|
166
|
+
const Y = new Un(W, v.domElement);
|
|
167
|
+
Y.target.set(0, 22, 0), Y.enableDamping = !1, Y.update(), Y.rotateSpeed = 1.6, Y.panSpeed = 1.6;
|
|
168
|
+
const C = new $n(W, v.domElement);
|
|
169
|
+
C.setMode("translate"), C.setSize(0.8);
|
|
170
|
+
const pe = new N.Box3(), je = (t) => {
|
|
171
|
+
if (!t) return;
|
|
172
|
+
t.updateMatrixWorld(!0), pe.setFromObject(t);
|
|
173
|
+
const s = pe.min.y;
|
|
174
|
+
Number.isFinite(s) && Math.abs(s) > 1e-4 && (t.position.y -= s, t.updateMatrixWorld(!0));
|
|
79
175
|
};
|
|
80
|
-
|
|
81
|
-
var
|
|
82
|
-
|
|
83
|
-
}),
|
|
84
|
-
let
|
|
85
|
-
const
|
|
86
|
-
|
|
176
|
+
C.addEventListener("dragging-changed", (t) => {
|
|
177
|
+
var s, R;
|
|
178
|
+
Y.enabled = !t.value, t.value || je(C.object), (R = (s = _.current).invalidate) == null || R.call(s);
|
|
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;
|
|
181
|
+
const ye = () => {
|
|
182
|
+
Ce = !0;
|
|
87
183
|
};
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
let
|
|
91
|
-
const
|
|
92
|
-
for (const
|
|
93
|
-
},
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
},
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
return
|
|
100
|
-
},
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
return
|
|
104
|
-
},
|
|
105
|
-
var
|
|
106
|
-
const
|
|
107
|
-
if (!
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
if (!
|
|
111
|
-
const
|
|
112
|
-
(
|
|
184
|
+
_.current.invalidate = ye, Y.addEventListener("change", ye), C.addEventListener("change", ye), v.domElement.addEventListener("pointermove", ye);
|
|
185
|
+
const Re = new N.Raycaster(), be = new N.Vector2();
|
|
186
|
+
let Se = null, i = null, S = 0;
|
|
187
|
+
const V = () => c.current.map((t) => t.mesh), p = () => {
|
|
188
|
+
for (const t of V()) t.material.emissive.setHex(t === i ? 44610 : t === Se ? 2055220 : 0);
|
|
189
|
+
}, O = () => c.current.length ? `${c.current.length} object(s) · selected: ${i ? i.userData.name : "—"} | M/R/S · left-drag to orbit · ? for shortcuts` : `hover: ${Se ? Se.userData.name : "—"} · selected: ${i ? i.userData.name : "—"} | left-drag to orbit · ? for shortcuts`, ue = (t) => {
|
|
190
|
+
const s = v.domElement.getBoundingClientRect();
|
|
191
|
+
be.x = (t.clientX - s.left) / s.width * 2 - 1, be.y = -((t.clientY - s.top) / s.height) * 2 + 1;
|
|
192
|
+
}, ve = () => {
|
|
193
|
+
Re.setFromCamera(be, W);
|
|
194
|
+
const t = Re.intersectObjects(V(), !1);
|
|
195
|
+
return t.length ? t[0].object : null;
|
|
196
|
+
}, Ee = () => {
|
|
197
|
+
Re.setFromCamera(be, W);
|
|
198
|
+
const t = Re.intersectObjects(V(), !1);
|
|
199
|
+
return t.length ? t[0] : null;
|
|
200
|
+
}, Z = (t) => {
|
|
201
|
+
var me;
|
|
202
|
+
const s = M.current;
|
|
203
|
+
if (!s) return;
|
|
204
|
+
ue(t);
|
|
205
|
+
const R = Ee();
|
|
206
|
+
if (!R || R.faceIndex == null) return;
|
|
207
|
+
const F = (ne) => [ne.x - s.cx, -ne.z - s.cy, ne.y - s.minz], re = F(R.point), U = F(W.position);
|
|
208
|
+
(me = r.current) == null || me.postMessage({
|
|
113
209
|
cmd: "paint",
|
|
114
|
-
facet:
|
|
115
|
-
hx:
|
|
116
|
-
hy:
|
|
117
|
-
hz:
|
|
118
|
-
cx:
|
|
119
|
-
cy:
|
|
120
|
-
cz:
|
|
121
|
-
radius:
|
|
122
|
-
enforcer:
|
|
210
|
+
facet: R.faceIndex,
|
|
211
|
+
hx: re[0],
|
|
212
|
+
hy: re[1],
|
|
213
|
+
hz: re[2],
|
|
214
|
+
cx: U[0],
|
|
215
|
+
cy: U[1],
|
|
216
|
+
cz: U[2],
|
|
217
|
+
radius: P.current,
|
|
218
|
+
enforcer: T.current === "enforcer"
|
|
123
219
|
});
|
|
124
|
-
},
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
},
|
|
128
|
-
if (
|
|
129
|
-
if (
|
|
130
|
-
|
|
220
|
+
}, q = () => {
|
|
221
|
+
const t = v.domElement;
|
|
222
|
+
t.style.cursor = b.current === "preview" ? "" : T.current !== "off" ? "crosshair" : Se ? "pointer" : "";
|
|
223
|
+
}, z = (t) => {
|
|
224
|
+
if (b.current === "preview") return;
|
|
225
|
+
if (T.current !== "off") {
|
|
226
|
+
G.current && Z(t);
|
|
131
227
|
return;
|
|
132
228
|
}
|
|
133
|
-
if (
|
|
134
|
-
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
},
|
|
138
|
-
if (
|
|
139
|
-
if (
|
|
140
|
-
|
|
229
|
+
if (C.dragging || C.axis) return;
|
|
230
|
+
ue(t);
|
|
231
|
+
const s = ve();
|
|
232
|
+
s !== Se && (Se = s, p(), q(), L(O()));
|
|
233
|
+
}, ie = (t) => {
|
|
234
|
+
if (t.button !== 0 || b.current === "preview") return;
|
|
235
|
+
if (T.current !== "off") {
|
|
236
|
+
G.current = !0, Y.enabled = !1, Z(t);
|
|
141
237
|
return;
|
|
142
238
|
}
|
|
143
|
-
if (
|
|
144
|
-
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
},
|
|
148
|
-
|
|
149
|
-
},
|
|
150
|
-
|
|
151
|
-
},
|
|
152
|
-
if (
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
|
|
239
|
+
if (C.dragging || C.axis) return;
|
|
240
|
+
ue(t);
|
|
241
|
+
const s = ve();
|
|
242
|
+
s ? (i = s, C.attach(s)) : (i = null, C.detach()), p(), L(O());
|
|
243
|
+
}, we = () => {
|
|
244
|
+
G.current && (G.current = !1, Y.enabled = !0);
|
|
245
|
+
}, se = (t) => {
|
|
246
|
+
t.button !== 0 || b.current === "preview" || T.current !== "off" || (ue(t), ve() ? Fe() : (i = null, C.detach(), p(), L(O())));
|
|
247
|
+
}, ae = (t) => {
|
|
248
|
+
if (T.current === "off" || b.current === "preview") return;
|
|
249
|
+
t.preventDefault(), t.stopPropagation();
|
|
250
|
+
const s = Math.min(15, Math.max(1, P.current + (t.deltaY < 0 ? 0.5 : -0.5)));
|
|
251
|
+
P.current = s, A(s);
|
|
156
252
|
};
|
|
157
|
-
let
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
},
|
|
161
|
-
if (
|
|
162
|
-
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
const
|
|
166
|
-
|
|
253
|
+
let J = null;
|
|
254
|
+
const ce = (t) => {
|
|
255
|
+
t.button === 2 && (J = { x: t.clientX, y: t.clientY });
|
|
256
|
+
}, ke = (t) => {
|
|
257
|
+
if (t.preventDefault(), b.current === "preview" || T.current !== "off" || J && Math.hypot(t.clientX - J.x, t.clientY - J.y) > 4) return;
|
|
258
|
+
ue(t);
|
|
259
|
+
const s = ve();
|
|
260
|
+
s ? (i = s, C.attach(s)) : (i = null, C.detach()), p(), L(O());
|
|
261
|
+
const R = v.domElement.getBoundingClientRect();
|
|
262
|
+
I({ x: t.clientX - R.left, y: t.clientY - R.top, onObject: !!s });
|
|
167
263
|
};
|
|
168
|
-
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
},
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
},
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
const
|
|
180
|
-
if (
|
|
181
|
-
|
|
264
|
+
v.domElement.addEventListener("pointermove", z), v.domElement.addEventListener("pointerdown", ie), v.domElement.addEventListener("pointerdown", ce), v.domElement.addEventListener("contextmenu", ke), v.domElement.addEventListener("dblclick", se), v.domElement.addEventListener("wheel", ae, { passive: !1, capture: !0 }), window.addEventListener("pointerup", we), window.addEventListener("pointercancel", we);
|
|
265
|
+
const ze = (t) => {
|
|
266
|
+
C.setMode(t), te(t);
|
|
267
|
+
}, Fe = () => {
|
|
268
|
+
const t = c.current, s = new N.Box3();
|
|
269
|
+
t.length ? t.forEach((U) => s.expandByObject(U.mesh)) : s.setFromCenterAndSize(new N.Vector3(0, 25, 0), new N.Vector3(100, 50, 100));
|
|
270
|
+
const R = s.getCenter(new N.Vector3()), F = s.getSize(new N.Vector3()), re = Math.max(F.x, F.y, F.z, 20) * 1.9 + 40;
|
|
271
|
+
Y.target.copy(R), W.position.set(R.x + re * 0.7, R.y + re * 0.55 + F.y * 0.3, R.z + re), W.updateProjectionMatrix(), Y.update();
|
|
272
|
+
}, qe = (t, s, R = null, F = null, re = null) => {
|
|
273
|
+
const U = new N.BufferGeometry();
|
|
274
|
+
U.setAttribute("position", new N.Float32BufferAttribute(s, 3)), U.computeVertexNormals(), U.computeBoundingBox();
|
|
275
|
+
const me = B.current[0] || "#6aa0dc", ne = new N.Mesh(U, new N.MeshStandardMaterial({ color: new N.Color(me), roughness: 0.6, metalness: 0.05, side: N.DoubleSide }));
|
|
276
|
+
if (R && ne.rotation.copy(R), F && ne.scale.copy(F), re)
|
|
277
|
+
ne.position.copy(re);
|
|
182
278
|
else {
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
const
|
|
186
|
-
|
|
279
|
+
const Ne = (U.boundingBox.max.x - U.boundingBox.min.x) * (F ? Math.abs(F.x) : 1);
|
|
280
|
+
c.current.length === 0 && (d.current = 0);
|
|
281
|
+
const Pe = E(m.current);
|
|
282
|
+
ne.position.set(Pe.x + d.current + Ne / 2, 0, Pe.z), d.current += Ne + 8;
|
|
187
283
|
}
|
|
188
|
-
|
|
189
|
-
const
|
|
190
|
-
return
|
|
284
|
+
ne.userData = { name: t }, ge.add(ne);
|
|
285
|
+
const Me = ++S;
|
|
286
|
+
return c.current.push({ id: Me, name: t, mesh: ne, localPos: s, extruder: 1, visible: !0 }), ge.visible = !0, Ie != null && We(), L(O()), Fe(), { id: Me, name: t };
|
|
191
287
|
};
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
288
|
+
let Ie = null;
|
|
289
|
+
function We() {
|
|
290
|
+
for (const t of c.current) {
|
|
291
|
+
const s = t.mesh.children.find((re) => {
|
|
292
|
+
var U;
|
|
293
|
+
return (U = re.userData) == null ? void 0 : U.overhang;
|
|
294
|
+
});
|
|
295
|
+
if (s && (t.mesh.remove(s), s.geometry.dispose(), s.material.dispose()), Ie == null) continue;
|
|
296
|
+
t.mesh.updateWorldMatrix(!0, !1);
|
|
297
|
+
const R = Er(t.mesh, Ie);
|
|
298
|
+
if (!R) continue;
|
|
299
|
+
const F = new N.Mesh(R, new N.MeshBasicMaterial({
|
|
300
|
+
color: 16729139,
|
|
301
|
+
transparent: !0,
|
|
302
|
+
opacity: 0.7,
|
|
303
|
+
side: N.DoubleSide,
|
|
304
|
+
depthWrite: !1,
|
|
305
|
+
polygonOffset: !0,
|
|
306
|
+
polygonOffsetFactor: -1,
|
|
307
|
+
polygonOffsetUnits: -1
|
|
308
|
+
}));
|
|
309
|
+
F.userData.overhang = !0, t.mesh.add(F);
|
|
310
|
+
}
|
|
311
|
+
ye();
|
|
312
|
+
}
|
|
313
|
+
C.addEventListener("dragging-changed", (t) => {
|
|
314
|
+
!t.value && Ie != null && We();
|
|
315
|
+
}), a.current = {
|
|
316
|
+
setMode: ze,
|
|
317
|
+
/** Highlight facets below `thresholdDeg` (the support threshold angle); null turns the shading off. */
|
|
318
|
+
setOverhang: (t) => {
|
|
319
|
+
Ie = t, We();
|
|
320
|
+
},
|
|
321
|
+
refreshCursor: () => q(),
|
|
322
|
+
// keeps the cursor hint in sync when the paint mode changes
|
|
196
323
|
detachTransform: () => {
|
|
197
|
-
|
|
324
|
+
i = null, C.detach(), p();
|
|
198
325
|
},
|
|
199
|
-
// 20
|
|
200
|
-
addObject: (
|
|
201
|
-
// ----
|
|
202
|
-
getSnapshot: (
|
|
203
|
-
const
|
|
204
|
-
return
|
|
326
|
+
// stage 20: release the gizmo when entering painting
|
|
327
|
+
addObject: (t, s) => qe(t, Mr(s).localPos),
|
|
328
|
+
// ---- Shortcut support (duplicate/nudge/rotate/zoom-to) ----
|
|
329
|
+
getSnapshot: (t) => {
|
|
330
|
+
const s = c.current.find((R) => R.id === t);
|
|
331
|
+
return s ? { name: s.name, localPos: s.localPos, rot: s.mesh.rotation.clone(), scale: s.mesh.scale.clone(), pos: s.mesh.position.clone() } : null;
|
|
205
332
|
},
|
|
206
|
-
// keepPos=true
|
|
207
|
-
spawnSnapshot: (
|
|
208
|
-
nudgeSelected: (
|
|
209
|
-
|
|
333
|
+
// keepPos=true keeps the snapshot's original position (split). false (default) places it beside via the placement cursor (duplicate/paste).
|
|
334
|
+
spawnSnapshot: (t, s = !1) => t ? qe(t.name, t.localPos, t.rot, t.scale, s && t.pos || null) : null,
|
|
335
|
+
nudgeSelected: (t, s) => {
|
|
336
|
+
i && (i.position.x += t, i.position.z += s);
|
|
210
337
|
},
|
|
211
|
-
rotateSelectedY: (
|
|
212
|
-
|
|
338
|
+
rotateSelectedY: (t) => {
|
|
339
|
+
i && (i.rotation.y += t);
|
|
213
340
|
},
|
|
214
|
-
frame: () =>
|
|
215
|
-
// Z:
|
|
341
|
+
frame: () => Fe(),
|
|
342
|
+
// Z: zoom to all objects
|
|
216
343
|
frameBed: () => {
|
|
217
|
-
const
|
|
218
|
-
|
|
344
|
+
const t = E(m.current), s = Math.max(K.current, h.current) * 1.1 + 40;
|
|
345
|
+
Y.target.set(t.x, 0, t.z), W.position.set(t.x + s * 0.55, s * 0.8, t.z + s), Y.update();
|
|
219
346
|
},
|
|
220
|
-
removeObject: (
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
347
|
+
removeObject: (t) => {
|
|
348
|
+
var re, U;
|
|
349
|
+
const s = c.current, R = s.findIndex((me) => me.id === t);
|
|
350
|
+
if (R < 0) return;
|
|
351
|
+
const F = s[R];
|
|
352
|
+
i === F.mesh && (i = null, C.detach()), Se === F.mesh && (Se = null);
|
|
353
|
+
for (const me of [...F.mesh.children])
|
|
354
|
+
F.mesh.remove(me), (re = me.geometry) == null || re.dispose(), (U = me.material) == null || U.dispose();
|
|
355
|
+
ge.remove(F.mesh), F.mesh.geometry.dispose(), F.mesh.material.dispose(), s.splice(R, 1), s.length === 0 && (d.current = 0), p(), L(O());
|
|
225
356
|
},
|
|
226
|
-
// MM:
|
|
227
|
-
platePos: (
|
|
228
|
-
//
|
|
229
|
-
plateOfObject: (
|
|
230
|
-
|
|
231
|
-
const
|
|
232
|
-
return
|
|
357
|
+
// MM: merges triangles sorted by ascending extruder -> group0 (ext1) followed by group1 (ext2); returns split.
|
|
358
|
+
platePos: (t) => E(t),
|
|
359
|
+
// three (x,z) offset of plate i
|
|
360
|
+
plateOfObject: (t) => {
|
|
361
|
+
t.mesh.updateMatrixWorld(!0);
|
|
362
|
+
const s = new N.Vector3().setFromMatrixPosition(t.mesh.matrixWorld);
|
|
363
|
+
return k(s.x, s.z);
|
|
233
364
|
},
|
|
234
|
-
// plateIdx!=null
|
|
235
|
-
buildMergedSTL: (
|
|
236
|
-
let
|
|
237
|
-
if (
|
|
238
|
-
|
|
239
|
-
const
|
|
240
|
-
return
|
|
241
|
-
})), !
|
|
242
|
-
const
|
|
243
|
-
let
|
|
244
|
-
for (const
|
|
245
|
-
(
|
|
246
|
-
const
|
|
247
|
-
for (let
|
|
248
|
-
|
|
249
|
-
|
|
365
|
+
// 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: (t = null) => {
|
|
367
|
+
let s = c.current.filter((X) => X.visible !== !1);
|
|
368
|
+
if (t != null && (s = s.filter((X) => {
|
|
369
|
+
X.mesh.updateMatrixWorld(!0);
|
|
370
|
+
const xe = new N.Vector3().setFromMatrixPosition(X.mesh.matrixWorld);
|
|
371
|
+
return k(xe.x, xe.z) === t;
|
|
372
|
+
})), !s.length) return null;
|
|
373
|
+
const R = [...s].sort((X, xe) => (X.extruder || 1) - (xe.extruder || 1)), F = new Set(R.map((X) => X.extruder || 1)), re = new N.Vector3(), U = [];
|
|
374
|
+
let me = 0, ne = 0;
|
|
375
|
+
for (const X of R) {
|
|
376
|
+
(X.extruder || 1) >= 2 && ne === 0 && (ne = me), X.mesh.updateMatrixWorld(!0);
|
|
377
|
+
const xe = X.mesh.matrixWorld, Ge = X.localPos;
|
|
378
|
+
for (let Ue = 0; Ue < Ge.length; Ue += 3)
|
|
379
|
+
re.set(Ge[Ue], Ge[Ue + 1], Ge[Ue + 2]).applyMatrix4(xe), U.push(re.x, -re.z, re.y);
|
|
380
|
+
me += Ge.length / 9;
|
|
250
381
|
}
|
|
251
|
-
let
|
|
252
|
-
for (let
|
|
253
|
-
|
|
254
|
-
const
|
|
255
|
-
for (let
|
|
256
|
-
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
let
|
|
260
|
-
for (let
|
|
261
|
-
|
|
262
|
-
for (let
|
|
263
|
-
|
|
264
|
-
|
|
382
|
+
let Me = 1e18, Ne = 1e18, Pe = -1e18, Ae = -1e18;
|
|
383
|
+
for (let X = 0; X < U.length; X += 3)
|
|
384
|
+
U[X] < Me && (Me = U[X]), U[X] > Pe && (Pe = U[X]), U[X + 1] < Ne && (Ne = U[X + 1]), U[X + 1] > Ae && (Ae = U[X + 1]);
|
|
385
|
+
const De = (Me + Pe) / 2, Oe = (Ne + Ae) / 2;
|
|
386
|
+
for (let X = 0; X < U.length; X += 3)
|
|
387
|
+
U[X] -= De, U[X + 1] -= Oe;
|
|
388
|
+
const Ze = De, fe = -Oe, le = new ArrayBuffer(84 + me * 50), Le = new DataView(le);
|
|
389
|
+
Le.setUint32(80, me, !0);
|
|
390
|
+
let _e = 84, Te = 0;
|
|
391
|
+
for (let X = 0; X < me; X++) {
|
|
392
|
+
_e += 12;
|
|
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;
|
|
265
396
|
}
|
|
266
|
-
return { buf:
|
|
397
|
+
return { buf: le, split: ne, extruders: F.size, offX: Ze, offZ: fe };
|
|
267
398
|
},
|
|
268
|
-
setObjectExtruder: (
|
|
269
|
-
const
|
|
270
|
-
if (
|
|
271
|
-
|
|
272
|
-
const
|
|
273
|
-
|
|
399
|
+
setObjectExtruder: (t, s) => {
|
|
400
|
+
const R = c.current.find((F) => F.id === t);
|
|
401
|
+
if (R) {
|
|
402
|
+
R.extruder = s;
|
|
403
|
+
const F = B.current[s - 1];
|
|
404
|
+
F && R.mesh.material.color.set(F);
|
|
274
405
|
}
|
|
275
406
|
},
|
|
276
|
-
setObjectVisible: (
|
|
277
|
-
const
|
|
278
|
-
|
|
407
|
+
setObjectVisible: (t, s) => {
|
|
408
|
+
const R = c.current.find((F) => F.id === t);
|
|
409
|
+
R && (R.visible = s, R.mesh.visible = s);
|
|
279
410
|
},
|
|
280
|
-
// 27
|
|
411
|
+
// stage 27: print toggle (eye icon)
|
|
281
412
|
recolorObjects: () => {
|
|
282
|
-
for (const
|
|
283
|
-
const
|
|
284
|
-
|
|
413
|
+
for (const t of c.current) {
|
|
414
|
+
const s = B.current[(t.extruder || 1) - 1];
|
|
415
|
+
s && t.mesh.material.color.set(s);
|
|
285
416
|
}
|
|
286
417
|
},
|
|
287
|
-
//
|
|
418
|
+
// reflect filament color changes
|
|
288
419
|
selectedObjectId: () => {
|
|
289
|
-
var
|
|
290
|
-
return
|
|
420
|
+
var t;
|
|
421
|
+
return i ? ((t = c.current.find((s) => s.mesh === i)) == null ? void 0 : t.id) ?? null : null;
|
|
291
422
|
},
|
|
292
|
-
// 27
|
|
293
|
-
selectObject: (
|
|
294
|
-
const
|
|
295
|
-
|
|
423
|
+
// stage 27: viewport toolbar "delete selected"
|
|
424
|
+
selectObject: (t) => {
|
|
425
|
+
const s = c.current.find((R) => R.id === t);
|
|
426
|
+
s && (i = s.mesh, C.attach(s.mesh), p(), L(O()));
|
|
296
427
|
},
|
|
297
|
-
// 28
|
|
298
|
-
// (
|
|
428
|
+
// 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
|
+
// (The upstream ensure_on_bed sinking allowance [allow_negative_z] is out of scope — we only seat by -min_z.)
|
|
299
430
|
placeOnBed: () => {
|
|
300
|
-
var
|
|
301
|
-
for (const
|
|
302
|
-
|
|
431
|
+
var t;
|
|
432
|
+
for (const s of c.current) s.mesh.position.y = 0;
|
|
433
|
+
i && ((t = C.update) == null || t.call(C));
|
|
303
434
|
},
|
|
304
435
|
onSliced: () => {
|
|
305
|
-
|
|
436
|
+
ge.visible = !1, C.detach(), i = null, p();
|
|
306
437
|
},
|
|
307
438
|
showObjects: () => {
|
|
308
|
-
|
|
439
|
+
ge.visible = !0;
|
|
309
440
|
},
|
|
310
|
-
// 29
|
|
311
|
-
setPlates: (
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
for (const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
const
|
|
318
|
-
for (let
|
|
319
|
-
for (let
|
|
320
|
-
const
|
|
321
|
-
const
|
|
322
|
-
return
|
|
441
|
+
// Stage 29-2: render N plates — each plate = grid + border, offset by PX_i, with the selected plate's border highlighted.
|
|
442
|
+
setPlates: (t, s, R, F) => {
|
|
443
|
+
const re = _.current;
|
|
444
|
+
K.current = s, h.current = R, w.current = t, m.current = F;
|
|
445
|
+
for (const fe of re.plateBeds || []) for (const le of [fe.gridThin, fe.gridBold, fe.border])
|
|
446
|
+
re.scene.remove(le), le.geometry.dispose(), le.material.dispose();
|
|
447
|
+
re.plateBeds = [];
|
|
448
|
+
const U = gt(t), me = Ye(s), ne = Ye(R), Me = Math.min(s, R), Ne = Me >= 6e3 ? 100 : Me >= 1200 ? 50 : Me >= 600 ? 20 : 10, Pe = [], Ae = [], De = -s / 2, Oe = -R / 2;
|
|
449
|
+
for (let fe = 0, le = De; le <= s / 2 + 1e-6; le = De + ++fe * Ne) (fe % 5 ? Pe : Ae).push(le, 0, Oe, le, 0, R / 2);
|
|
450
|
+
for (let fe = 0, le = Oe; le <= R / 2 + 1e-6; le = Oe + ++fe * Ne) (fe % 5 ? Pe : Ae).push(De, 0, le, s / 2, 0, le);
|
|
451
|
+
const Ze = (fe) => {
|
|
452
|
+
const le = new N.BufferGeometry();
|
|
453
|
+
return le.setAttribute("position", new N.Float32BufferAttribute(fe, 3)), le;
|
|
323
454
|
};
|
|
324
|
-
for (let
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
const
|
|
328
|
-
|
|
455
|
+
for (let fe = 0; fe < t; fe++) {
|
|
456
|
+
const le = fe % U * me, Le = Math.floor(fe / U) * ne, _e = new N.LineSegments(Ze(Pe), new N.LineBasicMaterial({ color: 2304561 })), Te = new N.LineSegments(Ze(Ae), new N.LineBasicMaterial({ color: 3752781 }));
|
|
457
|
+
_e.position.set(le, 0, Le), Te.position.set(le, 0, Le), re.scene.add(_e), re.scene.add(Te);
|
|
458
|
+
const X = fe === F, xe = new N.LineSegments(new N.EdgesGeometry(new N.PlaneGeometry(s, R)), new N.LineBasicMaterial({ color: X ? 44610 : 4871520, linewidth: X ? 2 : 1 }));
|
|
459
|
+
xe.rotation.x = -Math.PI / 2, xe.position.set(le, 0, Le), re.scene.add(xe), re.plateBeds.push({ gridThin: _e, gridBold: Te, border: xe });
|
|
329
460
|
}
|
|
330
461
|
},
|
|
331
|
-
setBed: (
|
|
332
|
-
var
|
|
333
|
-
(
|
|
462
|
+
setBed: (t, s) => {
|
|
463
|
+
var R;
|
|
464
|
+
(R = a.current) == null || R.setPlates(w.current, t, s, m.current);
|
|
334
465
|
}
|
|
335
|
-
//
|
|
466
|
+
// backwards compatible
|
|
336
467
|
};
|
|
337
|
-
const
|
|
338
|
-
var
|
|
339
|
-
(
|
|
468
|
+
const et = (t) => {
|
|
469
|
+
var s;
|
|
470
|
+
(s = l.current) == null || s.call(l, t), ye();
|
|
340
471
|
};
|
|
341
|
-
window.addEventListener("keydown",
|
|
342
|
-
const
|
|
343
|
-
|
|
472
|
+
window.addEventListener("keydown", et);
|
|
473
|
+
const tt = new ResizeObserver(() => {
|
|
474
|
+
g = j.clientWidth || g, y = j.clientHeight || y, W.aspect = g / y, W.updateProjectionMatrix(), v.setSize(g, y), ye();
|
|
344
475
|
});
|
|
345
|
-
|
|
346
|
-
let
|
|
347
|
-
const
|
|
348
|
-
|
|
476
|
+
tt.observe(j), L(O());
|
|
477
|
+
let nt = 0, Xe = 0;
|
|
478
|
+
const rt = (t = 0) => {
|
|
479
|
+
nt = requestAnimationFrame(rt), Y.update(), (Ce || t - Xe > 500) && (Ce = !1, Xe = t, v.render(D, W));
|
|
349
480
|
};
|
|
350
|
-
return
|
|
351
|
-
cancelAnimationFrame(
|
|
352
|
-
|
|
353
|
-
}),
|
|
481
|
+
return rt(), () => {
|
|
482
|
+
cancelAnimationFrame(nt), tt.disconnect(), window.removeEventListener("keydown", et), v.domElement.removeEventListener("pointermove", z), v.domElement.removeEventListener("pointerdown", ie), v.domElement.removeEventListener("pointerdown", ce), v.domElement.removeEventListener("contextmenu", ke), v.domElement.removeEventListener("dblclick", se), v.domElement.removeEventListener("wheel", ae, { capture: !0 }), window.removeEventListener("pointerup", we), window.removeEventListener("pointercancel", we), a.current = null, C.detach(), C.dispose(), Y.dispose(), D.traverse((t) => {
|
|
483
|
+
t.geometry && t.geometry.dispose(), t.material && t.material.dispose();
|
|
484
|
+
}), v.dispose(), v.domElement.parentNode && v.domElement.parentNode.removeChild(v.domElement);
|
|
354
485
|
};
|
|
355
|
-
}, []),
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
function un() {
|
|
403
|
-
const e = (r, a) => {
|
|
404
|
-
const l = gt(L, r), d = parseFloat(l);
|
|
405
|
-
return Number.isFinite(d) ? d : a;
|
|
406
|
-
}, t = e("outer_wall_speed", 60);
|
|
407
|
-
return {
|
|
408
|
-
speedByType: {
|
|
409
|
-
1: t,
|
|
410
|
-
2: e("sparse_infill_speed", 40),
|
|
411
|
-
3: e("internal_solid_infill_speed", 45),
|
|
412
|
-
4: t,
|
|
413
|
-
5: e("support_speed", 35),
|
|
414
|
-
6: e("support_speed", 35),
|
|
415
|
-
7: e("gap_infill_speed", 30),
|
|
416
|
-
8: t,
|
|
417
|
-
9: e("bridge_speed", 25),
|
|
418
|
-
10: e("ironing_speed", 20),
|
|
419
|
-
11: t
|
|
420
|
-
},
|
|
421
|
-
firstLayerSpeed: e("initial_layer_speed", 30),
|
|
422
|
-
closeFanLayers: e("close_fan_the_first_x_layers", 1),
|
|
423
|
-
fanNormal: e("fan_max_speed", 100),
|
|
424
|
-
tempNormal: e("nozzle_temperature", 210),
|
|
425
|
-
tempFirst: e("nozzle_temperature_initial_layer", e("nozzle_temperature", 210))
|
|
426
|
-
};
|
|
427
|
-
}
|
|
428
|
-
function Zt() {
|
|
429
|
-
const e = un();
|
|
430
|
-
for (const t of Object.values(y.current)) {
|
|
431
|
-
const r = Vn(t.seg, vt.current, e);
|
|
432
|
-
t.ctl.setColors(r.color), t.ctl === U.current && Nt({ min: r.min, max: r.max, label: r.label, unit: r.unit, cont: r.cont });
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
function cr() {
|
|
436
|
-
const e = se.current, t = Q.current || [];
|
|
437
|
-
if (!t.length) {
|
|
438
|
-
ct(e), Ne(0), U.current = null, le.current = null;
|
|
439
|
-
return;
|
|
440
|
-
}
|
|
441
|
-
const r = Pt(e, t);
|
|
442
|
-
if (!r) {
|
|
443
|
-
Ne(0);
|
|
444
|
-
return;
|
|
445
|
-
}
|
|
446
|
-
U.current = r.ctl, le.current = r.seg, r.ctl.setLayerRange(ue.current, ee.current), Zt(), Ne(r.seg.nSeg), zt(Fn(r.seg.typeLengths));
|
|
447
|
-
}
|
|
448
|
-
function dr() {
|
|
449
|
-
var e;
|
|
450
|
-
(e = U.current) == null || e.setLayerRange(ue.current, ee.current);
|
|
451
|
-
}
|
|
452
|
-
const dt = g(null), Ve = g(0), $e = () => {
|
|
453
|
-
Ve.current && (clearInterval(Ve.current), Ve.current = 0);
|
|
454
|
-
}, pr = (e, t) => {
|
|
455
|
-
const r = t > 2 ? (t - 2) / 2 : 0;
|
|
456
|
-
return r ? e <= r ? 0.15 * (e / r) : e === r + 1 ? 0.2 : e === r + 2 ? 0.6 : 0.6 + 0.4 * ((e - r - 2) / r) : t ? e / t : 0;
|
|
457
|
-
}, ur = (e) => {
|
|
458
|
-
const t = dt.current;
|
|
459
|
-
!t || Ve.current || (Ve.current = setInterval(() => {
|
|
460
|
-
const r = t.arr[0];
|
|
461
|
-
Ze(0.2 + 0.4 * Math.min(0.95, r / (3.5 * e)));
|
|
486
|
+
}, []), { mountRef: u, three: _ };
|
|
487
|
+
}
|
|
488
|
+
function Cr(n) {
|
|
489
|
+
const {
|
|
490
|
+
settings: a,
|
|
491
|
+
wipeTowerReal: c,
|
|
492
|
+
workerRef: l,
|
|
493
|
+
apiRef: r,
|
|
494
|
+
layersDataRef: m,
|
|
495
|
+
layerLoRef: d,
|
|
496
|
+
layerHiRef: w,
|
|
497
|
+
rebuildToolpaths: b,
|
|
498
|
+
rebuildPaintOverlay: T,
|
|
499
|
+
setProgress: P,
|
|
500
|
+
setSlicing: M,
|
|
501
|
+
setError: B,
|
|
502
|
+
setStats: ee,
|
|
503
|
+
setOverBed: L,
|
|
504
|
+
setLayerCount: te,
|
|
505
|
+
setLayerLo: I,
|
|
506
|
+
setLayerHi: A,
|
|
507
|
+
setGcodeUrl: u,
|
|
508
|
+
setCanvasMode: _,
|
|
509
|
+
setPaintCounts: G
|
|
510
|
+
} = n, K = H(null), h = H(null), E = H(!1), k = H(null), j = H(null), f = H(0), g = () => {
|
|
511
|
+
f.current && (clearInterval(f.current), f.current = 0);
|
|
512
|
+
}, y = () => {
|
|
513
|
+
const i = j.current;
|
|
514
|
+
if (console.info("[vp-cancel] cancelSlice, hasView=", !!(i != null && i.cancel)), i != null && i.cancel)
|
|
515
|
+
try {
|
|
516
|
+
Atomics.store(i.cancel, 0, 1);
|
|
517
|
+
} catch {
|
|
518
|
+
i.cancel[0] = 1;
|
|
519
|
+
}
|
|
520
|
+
}, v = (i, S) => {
|
|
521
|
+
const V = S > 2 ? (S - 2) / 2 : 0;
|
|
522
|
+
return V ? i <= V ? 0.35 * (i / V) : i === V + 1 ? 0.36 : i === V + 2 ? 0.87 : 0.87 + 0.13 * ((i - V - 2) / V) : S ? i / S : 0;
|
|
523
|
+
}, D = (i) => {
|
|
524
|
+
const S = j.current;
|
|
525
|
+
S && (g(), f.current = setInterval(() => {
|
|
526
|
+
const V = S.arr[0];
|
|
527
|
+
P(0.36 + 0.51 * Math.min(0.95, V / (3.5 * i)));
|
|
528
|
+
}, 150));
|
|
529
|
+
}, W = () => {
|
|
530
|
+
const i = j.current;
|
|
531
|
+
i && (g(), f.current = setInterval(() => {
|
|
532
|
+
P(0.35 * Math.min(1, i.arr[0] / 1e3));
|
|
462
533
|
}, 150));
|
|
463
534
|
};
|
|
464
|
-
function
|
|
465
|
-
if (!
|
|
466
|
-
const
|
|
467
|
-
|
|
468
|
-
var
|
|
469
|
-
const
|
|
470
|
-
if (
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
} else if (
|
|
535
|
+
function oe() {
|
|
536
|
+
if (!l.current) {
|
|
537
|
+
const i = Hn();
|
|
538
|
+
i.onmessage = (V) => {
|
|
539
|
+
var ue, ve, Ee, Z, q;
|
|
540
|
+
const p = V.data, O = K.current;
|
|
541
|
+
if (p.type === "progress") {
|
|
542
|
+
const z = p.total > 2 ? (p.total - 2) / 2 : 0;
|
|
543
|
+
z && p.done <= z && g(), z && p.done === z + 1 && D(z), z && p.done >= z + 2 && g(), P(v(p.done, p.total)), (ue = O == null ? void 0 : O.note) == null || ue.call(O, p.done, p.total), (ve = O == null ? void 0 : O.kick) == null || ve.call(O);
|
|
544
|
+
} else if (p.type === "supsab")
|
|
474
545
|
try {
|
|
475
|
-
|
|
476
|
-
} catch {
|
|
546
|
+
j.current = { arr: new Uint32Array(p.buf, p.ptr, 1), cancel: p.cancelPtr ? new Uint32Array(p.buf, p.cancelPtr, 1) : null }, console.info("[vp-cancel] supsab cancelPtr=", p.cancelPtr);
|
|
547
|
+
} catch (z) {
|
|
548
|
+
console.info("[vp-cancel] supsab view fail", z);
|
|
477
549
|
}
|
|
478
|
-
else if (
|
|
479
|
-
(
|
|
480
|
-
const
|
|
481
|
-
|
|
482
|
-
} else
|
|
550
|
+
else if (p.type === "layer") {
|
|
551
|
+
(Ee = O == null ? void 0 : O.kick) == null || Ee.call(O);
|
|
552
|
+
const z = h.current;
|
|
553
|
+
z && (z.layers.push({ z: p.z, paths: p.paths, widths: p.widths }), p.gcode && z.gcode.push(p.gcode));
|
|
554
|
+
} else p.type === "done" ? (g(), O ? (K.current = null, (Z = O.stop) == null || Z.call(O), O.resolve(ge(p.result))) : (de(ge(p.result)), M(!1))) : p.type === "error" ? (g(), O ? (K.current = null, (q = O.stop) == null || q.call(O), O.reject(new Error(p.error))) : (B("Slice failed: " + p.error), M(!1))) : p.type === "prepared" || (p.type === "painted" ? (G({ enf: p.enf, blk: p.blk }), i.postMessage({ cmd: "overlay" })) : p.type === "overlay" && T(p.enf, p.blk));
|
|
483
555
|
};
|
|
484
|
-
const
|
|
485
|
-
var
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
556
|
+
const S = (V) => {
|
|
557
|
+
var O;
|
|
558
|
+
if (l.current !== i) return;
|
|
559
|
+
g(), j.current = null;
|
|
560
|
+
const p = K.current;
|
|
561
|
+
if (p) {
|
|
562
|
+
K.current = null, (O = p.stop) == null || O.call(p);
|
|
490
563
|
try {
|
|
491
|
-
|
|
564
|
+
i.terminate();
|
|
492
565
|
} catch {
|
|
493
566
|
}
|
|
494
|
-
|
|
567
|
+
l.current = null, p.reject(new Error(V));
|
|
495
568
|
} else
|
|
496
|
-
|
|
569
|
+
B(V), M(!1);
|
|
497
570
|
};
|
|
498
|
-
|
|
499
|
-
}
|
|
500
|
-
return z.current;
|
|
501
|
-
}
|
|
502
|
-
function mn(e) {
|
|
503
|
-
if (e && e.stats && e.stats.streamed) {
|
|
504
|
-
const t = yt.current || { layers: [], gcode: [] };
|
|
505
|
-
return { stats: e.stats, layers: t.layers, gcode: t.gcode.join("") };
|
|
571
|
+
i.onerror = (V) => S("Worker terminated (likely out of memory): " + (V.message || "worker error")), i.onmessageerror = () => S("Worker message error (structured clone failed)"), l.current = i, typeof window < "u" && (window.__vpWorker = i);
|
|
506
572
|
}
|
|
507
|
-
return
|
|
573
|
+
return l.current;
|
|
508
574
|
}
|
|
509
|
-
function
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
return;
|
|
575
|
+
function ge(i) {
|
|
576
|
+
if (i && i.stats && i.stats.streamed) {
|
|
577
|
+
const S = h.current || { layers: [], gcode: [] };
|
|
578
|
+
return { stats: i.stats, layers: S.layers, gcode: S.gcode.join("") };
|
|
514
579
|
}
|
|
515
|
-
|
|
516
|
-
const t = e.layers.length;
|
|
517
|
-
ue.current = 0, ee.current = t - 1, _t(0), St(t - 1), cr(), (r = c.current) == null || r.onSliced(), _e("preview"), at({ layers: e.stats.layers, segments: e.stats.path_segments, filament: e.stats.filament_mm, timeSec: e.stats.time_estimate }), ot(!!e.stats.over_bed), lt(t), it((a) => (a && URL.revokeObjectURL(a), URL.createObjectURL(new Blob([e.gcode], { type: "text/plain" }))));
|
|
580
|
+
return i;
|
|
518
581
|
}
|
|
519
|
-
|
|
520
|
-
var
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
r && _("지원 포맷: STL/OBJ/3MF/AMF/PLY");
|
|
582
|
+
function de(i) {
|
|
583
|
+
var V;
|
|
584
|
+
if (i.error) {
|
|
585
|
+
B(String(i.error));
|
|
524
586
|
return;
|
|
525
587
|
}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
}
|
|
537
|
-
rt(w.current.map((s) => ({ id: s.id, name: s.name, extruder: s.extruder, visible: s.visible !== !1 }))), a > 1e5 && Yt(`삼각형 ${Math.round(a).toLocaleString()}개 — 슬라이스가 오래 걸릴 수 있습니다`);
|
|
538
|
-
}
|
|
539
|
-
function fr(e) {
|
|
540
|
-
fn(e.target.files), e.target.value = "";
|
|
541
|
-
}
|
|
542
|
-
function Bt(e) {
|
|
543
|
-
var t;
|
|
544
|
-
(t = c.current) == null || t.removeObject(e), rt(w.current.map((r) => ({ id: r.id, name: r.name, extruder: r.extruder, visible: r.visible !== !1 })));
|
|
545
|
-
}
|
|
546
|
-
function br(e) {
|
|
547
|
-
var t;
|
|
548
|
-
e.preventDefault(), Lt(!1), fn((t = e.dataTransfer) == null ? void 0 : t.files);
|
|
549
|
-
}
|
|
550
|
-
function hr(e) {
|
|
551
|
-
e.preventDefault(), e.dataTransfer && (e.dataTransfer.dropEffect = "copy"), Rt || Lt(!0);
|
|
552
|
-
}
|
|
553
|
-
function gr(e) {
|
|
554
|
-
e.currentTarget.contains(e.relatedTarget) || Lt(!1);
|
|
588
|
+
m.current = i.layers;
|
|
589
|
+
const S = i.layers.length;
|
|
590
|
+
d.current = 0, w.current = S - 1, I(0), A(S - 1), b(), (V = r.current) == null || V.onSliced(), _("preview"), ee({
|
|
591
|
+
layers: i.stats.layers,
|
|
592
|
+
segments: i.stats.path_segments,
|
|
593
|
+
filament: i.stats.filament_mm,
|
|
594
|
+
timeSec: i.stats.time_estimate,
|
|
595
|
+
engine: i.stats.time_engine,
|
|
596
|
+
limits: i.stats.machine_limits
|
|
597
|
+
}), L(!!i.stats.over_bed), te(S), u((p) => (p && URL.revokeObjectURL(p), URL.createObjectURL(new Blob([i.gcode], { type: "text/plain" }))));
|
|
555
598
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
for (const u of ["enf", "blk"]) l[u] && (r.objectsGroup.remove(l[u]), l[u].geometry.dispose(), l[u].material.dispose());
|
|
563
|
-
const d = (u, P) => {
|
|
564
|
-
if (!u || u.length < 9) return null;
|
|
565
|
-
const m = new Float32Array(u.length);
|
|
566
|
-
for (let T = 0; T < u.length; T += 3) {
|
|
567
|
-
const Y = u[T], M = u[T + 1], j = u[T + 2];
|
|
568
|
-
m[T] = Y + a.cx, m[T + 1] = j + a.minz, m[T + 2] = -(M + a.cy);
|
|
569
|
-
}
|
|
570
|
-
const h = new f.BufferGeometry();
|
|
571
|
-
h.setAttribute("position", new f.Float32BufferAttribute(m, 3)), h.computeVertexNormals();
|
|
572
|
-
const I = new f.Mesh(h, new f.MeshBasicMaterial({ color: P, transparent: !0, opacity: 0.55, side: f.DoubleSide, depthTest: !1 }));
|
|
573
|
-
return I.renderOrder = 999, r.objectsGroup.add(I), I;
|
|
574
|
-
};
|
|
575
|
-
Je.current = { enf: d(e, 2845951), blk: d(t, 14826299) }, (b = (s = N.current).invalidate) == null || b.call(s);
|
|
576
|
-
}
|
|
577
|
-
function vr() {
|
|
578
|
-
const e = N.current, t = Je.current;
|
|
579
|
-
if (t && e.objectsGroup)
|
|
580
|
-
for (const r of ["enf", "blk"]) t[r] && (e.objectsGroup.remove(t[r]), t[r].geometry.dispose(), t[r].material.dispose());
|
|
581
|
-
Je.current = null;
|
|
582
|
-
}
|
|
583
|
-
function re(e) {
|
|
584
|
-
var t, r, a;
|
|
585
|
-
if (e !== "off" && w.current.length === 0) {
|
|
586
|
-
_("먼저 STL 을 업로드하세요");
|
|
587
|
-
return;
|
|
588
|
-
}
|
|
589
|
-
if (e !== "off") {
|
|
590
|
-
const l = (t = c.current) == null ? void 0 : t.buildMergedSTL(se.current);
|
|
591
|
-
if (!l) return;
|
|
592
|
-
wt.current = { cx: l.offX, cy: -l.offZ, minz: 0 }, (r = c.current) == null || r.detachTransform(), Ue().postMessage({ cmd: "prepare", stl: l.buf });
|
|
599
|
+
Ve(() => () => {
|
|
600
|
+
l.current && (l.current.terminate(), l.current = null);
|
|
601
|
+
}, []), Ve(() => {
|
|
602
|
+
try {
|
|
603
|
+
oe().postMessage({ cmd: "warmup" });
|
|
604
|
+
} catch {
|
|
593
605
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
function
|
|
597
|
-
|
|
598
|
-
}
|
|
599
|
-
const yr = 6e4, kr = 3e5;
|
|
600
|
-
function bn(e, t) {
|
|
601
|
-
return new Promise((r, a) => {
|
|
606
|
+
}, []);
|
|
607
|
+
const Y = 6e4, C = 3e5;
|
|
608
|
+
function pe(i, S) {
|
|
609
|
+
return new Promise((V, p) => {
|
|
602
610
|
if (typeof window < "u" && window.__vpFail && window.__vpFail(window.__vpSliceN = (window.__vpSliceN || 0) + 1)) {
|
|
603
|
-
|
|
611
|
+
p(new Error("forced failure (test hook)"));
|
|
604
612
|
return;
|
|
605
613
|
}
|
|
606
|
-
const
|
|
607
|
-
|
|
608
|
-
let
|
|
609
|
-
const
|
|
610
|
-
let
|
|
611
|
-
const
|
|
612
|
-
|
|
613
|
-
const
|
|
614
|
-
|
|
615
|
-
},
|
|
616
|
-
const
|
|
617
|
-
return
|
|
618
|
-
},
|
|
619
|
-
|
|
620
|
-
},
|
|
621
|
-
|
|
622
|
-
const
|
|
623
|
-
|
|
624
|
-
var
|
|
625
|
-
|
|
614
|
+
const O = typeof window < "u" && window.__vpStallNext ? (window.__vpStallNext = !1, !0) : !1, ue = typeof window < "u" && window.__vpWatchdogOnce ? ((J) => (window.__vpWatchdogOnce = 0, J))(window.__vpWatchdogOnce) : Y;
|
|
615
|
+
h.current = { layers: [], gcode: [] };
|
|
616
|
+
let ve = 0, Ee = 0, Z = 0;
|
|
617
|
+
const q = performance.now();
|
|
618
|
+
let z = "";
|
|
619
|
+
const ie = (J, ce) => {
|
|
620
|
+
Ee = J, Z = ce;
|
|
621
|
+
const ke = ce > 2 ? (ce - 2) / 2 : 0, ze = ke ? J < ke ? "PASS1…" : J === ke ? "PASS1-done" : J === ke + 1 ? "surf-done" : J === ke + 2 ? "support-done" : J === ce ? "emit-done" : "emit…" : "";
|
|
622
|
+
ze && ze !== z && (console.info(`[vp-prof] ${ze} +${((performance.now() - q) / 1e3).toFixed(1)}s`), z = ze);
|
|
623
|
+
}, we = () => {
|
|
624
|
+
const J = Z > 2 ? (Z - 2) / 2 : 0;
|
|
625
|
+
return J && Ee >= J && Ee < J + 2 ? C : ue;
|
|
626
|
+
}, se = () => {
|
|
627
|
+
ve && (clearTimeout(ve), ve = 0);
|
|
628
|
+
}, ae = () => {
|
|
629
|
+
se();
|
|
630
|
+
const J = we();
|
|
631
|
+
ve = setTimeout(() => {
|
|
632
|
+
var ce;
|
|
633
|
+
K.current = null, g(), j.current = null;
|
|
626
634
|
try {
|
|
627
|
-
(
|
|
635
|
+
(ce = l.current) == null || ce.terminate();
|
|
628
636
|
} catch {
|
|
629
637
|
}
|
|
630
|
-
|
|
631
|
-
},
|
|
638
|
+
l.current = null, p(new Error(`watchdog: no progress for ${J}ms — assuming memory pressure`));
|
|
639
|
+
}, J);
|
|
632
640
|
};
|
|
633
|
-
|
|
641
|
+
K.current = { resolve: V, reject: p, kick: ae, stop: se, note: ie }, ae(), oe().postMessage({ stl: i, params: S, stall: O }), W();
|
|
634
642
|
});
|
|
635
643
|
}
|
|
636
|
-
function
|
|
637
|
-
var
|
|
644
|
+
function je() {
|
|
645
|
+
var i;
|
|
638
646
|
try {
|
|
639
|
-
(
|
|
647
|
+
(i = l.current) == null || i.terminate();
|
|
640
648
|
} catch {
|
|
641
649
|
}
|
|
642
|
-
|
|
650
|
+
l.current = null, oe();
|
|
651
|
+
}
|
|
652
|
+
async function Ce(i, S) {
|
|
653
|
+
const V = (p) => String((p == null ? void 0 : p.message) || p).includes("canceled");
|
|
654
|
+
try {
|
|
655
|
+
const p = await pe(i, JSON.stringify(S));
|
|
656
|
+
return { r: p, economy: !!(p.stats && p.stats.economy) };
|
|
657
|
+
} catch (p) {
|
|
658
|
+
if (V(p)) throw p;
|
|
659
|
+
if (S.wall_generator !== "classic") {
|
|
660
|
+
je();
|
|
661
|
+
try {
|
|
662
|
+
const ue = await pe(i, JSON.stringify({ ...S, wall_generator: "classic", keep_stages: !1, reuse_stages: 0 }));
|
|
663
|
+
return { r: ue, economy: !!(ue.stats && ue.stats.economy), classicWalls: !0 };
|
|
664
|
+
} catch (ue) {
|
|
665
|
+
if (V(ue)) throw ue;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
return je(), { r: await pe(i, JSON.stringify({ ...S, economy: !0, keep_stages: !1, reuse_stages: 0 })), economy: !0, recovered: !0 };
|
|
669
|
+
}
|
|
643
670
|
}
|
|
644
|
-
async function
|
|
671
|
+
async function ye(i) {
|
|
645
672
|
try {
|
|
646
|
-
const
|
|
647
|
-
return
|
|
673
|
+
const S = await crypto.subtle.digest("SHA-256", i);
|
|
674
|
+
return Array.from(new Uint8Array(S, 0, 8)).map((V) => V.toString(16).padStart(2, "0")).join("");
|
|
648
675
|
} catch {
|
|
649
|
-
return
|
|
676
|
+
return null;
|
|
650
677
|
}
|
|
651
678
|
}
|
|
652
|
-
function
|
|
653
|
-
|
|
654
|
-
|
|
679
|
+
function Re(i, S) {
|
|
680
|
+
i.economy || (i.keep_stages = !0, i.reuse_stages = S && S === k.current ? 2 : 0);
|
|
681
|
+
}
|
|
682
|
+
function be(i) {
|
|
683
|
+
const S = xt(a);
|
|
684
|
+
return i.extruders >= 2 && i.split > 0 && (S.extruder_count = i.extruders, S.mm_group_split = i.split, S.wipe_tower_real = c), E.current && (S.sparse_infill_pattern = "rectilinear", S.infill_density = Math.min(S.infill_density ?? 0.15, 0.08), S.economy = !0), typeof window < "u" && window.__vpForceTree && (S.enable_support = !0, S.support_style = "tree", S.support_threshold_angle = 40), S;
|
|
685
|
+
}
|
|
686
|
+
async function Se(i) {
|
|
687
|
+
const S = be(i), V = await ye(i.buf);
|
|
688
|
+
Re(S, V);
|
|
689
|
+
try {
|
|
690
|
+
const p = await Ce(i.buf, S);
|
|
691
|
+
return k.current = p.economy || p.classicWalls ? null : V, { ...p, params: S };
|
|
692
|
+
} catch (p) {
|
|
693
|
+
throw k.current = null, p;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
return { getWorker: oe, cancelSlice: y, runSlice: Se, pendingSliceRef: K, downgradeRef: E };
|
|
697
|
+
}
|
|
698
|
+
function Sr(n) {
|
|
699
|
+
const {
|
|
700
|
+
three: a,
|
|
701
|
+
plateTpRef: c,
|
|
702
|
+
toolpathRef: l,
|
|
703
|
+
segDataRef: r,
|
|
704
|
+
layersDataRef: m,
|
|
705
|
+
plateResultsRef: d,
|
|
706
|
+
plateOffsetsRef: w,
|
|
707
|
+
lineWidthRef: b,
|
|
708
|
+
showTravelRef: T,
|
|
709
|
+
viewTypeRef: P,
|
|
710
|
+
layerLoRef: M,
|
|
711
|
+
layerHiRef: B,
|
|
712
|
+
selectedPlateRef: ee,
|
|
713
|
+
settings: L,
|
|
714
|
+
setSegCount: te,
|
|
715
|
+
setColorRange: I,
|
|
716
|
+
setRoleLegend: A
|
|
717
|
+
} = n;
|
|
718
|
+
function u(f) {
|
|
719
|
+
var y;
|
|
720
|
+
const g = c.current[f];
|
|
721
|
+
g && (g.group.remove(g.ctl.mesh), g.group.remove(g.ctl.travLines), g.ctl.dispose(), (y = a.current.toolpathGroup) == null || y.remove(g.group), delete c.current[f], l.current === g.ctl && (l.current = null, r.current = null));
|
|
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;
|
|
736
|
+
}
|
|
737
|
+
function K() {
|
|
738
|
+
for (const [f, g] of Object.entries(d.current)) {
|
|
739
|
+
const y = Number(f);
|
|
740
|
+
if (!g || g.error || !g.layers || !g.layers.length) continue;
|
|
741
|
+
const v = c.current[y];
|
|
742
|
+
(!v || v.layers !== g.layers) && G(y, g.layers);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
function h() {
|
|
746
|
+
const f = (y, v) => {
|
|
747
|
+
const D = Je(L, y), W = parseFloat(D);
|
|
748
|
+
return Number.isFinite(W) ? W : v;
|
|
749
|
+
}, g = f("outer_wall_speed", 60);
|
|
750
|
+
return {
|
|
751
|
+
speedByType: {
|
|
752
|
+
1: g,
|
|
753
|
+
2: f("sparse_infill_speed", 40),
|
|
754
|
+
3: f("internal_solid_infill_speed", 45),
|
|
755
|
+
4: g,
|
|
756
|
+
5: f("support_speed", 35),
|
|
757
|
+
6: f("support_speed", 35),
|
|
758
|
+
7: f("gap_infill_speed", 30),
|
|
759
|
+
8: g,
|
|
760
|
+
9: f("bridge_speed", 25),
|
|
761
|
+
10: f("ironing_speed", 20),
|
|
762
|
+
11: g
|
|
763
|
+
},
|
|
764
|
+
firstLayerSpeed: f("initial_layer_speed", 30),
|
|
765
|
+
closeFanLayers: f("close_fan_the_first_x_layers", 1),
|
|
766
|
+
fanNormal: f("fan_max_speed", 100),
|
|
767
|
+
tempNormal: f("nozzle_temperature", 210),
|
|
768
|
+
tempFirst: f("nozzle_temperature_initial_layer", f("nozzle_temperature", 210))
|
|
769
|
+
};
|
|
655
770
|
}
|
|
656
|
-
function
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
771
|
+
function E() {
|
|
772
|
+
const f = h();
|
|
773
|
+
for (const g of Object.values(c.current)) {
|
|
774
|
+
const y = Dt(g.seg, P.current, f);
|
|
775
|
+
g.ctl.setColors(y.color), g.ctl === l.current && I({ min: y.min, max: y.max, label: y.label, unit: y.unit, cont: y.cont });
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
function k() {
|
|
779
|
+
const f = ee.current, g = m.current || [];
|
|
780
|
+
if (!g.length) {
|
|
781
|
+
u(f), te(0), l.current = null, r.current = null;
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
const y = G(f, g);
|
|
785
|
+
if (!y) {
|
|
786
|
+
te(0);
|
|
664
787
|
return;
|
|
665
788
|
}
|
|
666
|
-
|
|
667
|
-
const a = r.layers.length;
|
|
668
|
-
ue.current = 0, ee.current = a - 1, _t(0), St(a - 1);
|
|
669
|
-
const l = y.current[e], d = l && l.layers === r.layers ? l : Pt(e, r.layers);
|
|
670
|
-
d && (U.current = d.ctl, le.current = d.seg, d.ctl.setLayerRange(0, a - 1), Zt(), Ne(d.seg.nSeg), zt(Fn(d.seg.typeLengths))), (s = c.current) == null || s.onSliced(), _e("preview"), at({ layers: r.stats.layers, segments: r.stats.path_segments, filament: r.stats.filament_mm, timeSec: r.stats.time_estimate }), ot(!!r.stats.over_bed), lt(a), it((b) => (b && URL.revokeObjectURL(b), URL.createObjectURL(new Blob([r.gcode], { type: "text/plain" }))));
|
|
789
|
+
l.current = y.ctl, r.current = y.seg, y.ctl.setLayerRange(M.current, B.current), E(), te(y.seg.nSeg), A(It(y.seg.typeLengths));
|
|
671
790
|
}
|
|
672
|
-
function
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
791
|
+
function j() {
|
|
792
|
+
var f;
|
|
793
|
+
(f = l.current) == null || f.setLayerRange(M.current, B.current);
|
|
794
|
+
}
|
|
795
|
+
return { disposePlateToolpath: u, clearToolpaths: _, buildPlateToolpath: G, ensurePlateToolpaths: K, viewCtx: h, applyViewColors: E, rebuildToolpaths: k, applyLayerRange: j };
|
|
796
|
+
}
|
|
797
|
+
function Rr(n) {
|
|
798
|
+
const {
|
|
799
|
+
apiRef: a,
|
|
800
|
+
selectedPlateRef: c,
|
|
801
|
+
plateCountRef: l,
|
|
802
|
+
placeXRef: r,
|
|
803
|
+
plateResultsRef: m,
|
|
804
|
+
plateOffsetsRef: d,
|
|
805
|
+
plateTpRef: w,
|
|
806
|
+
layersDataRef: b,
|
|
807
|
+
toolpathRef: T,
|
|
808
|
+
segDataRef: P,
|
|
809
|
+
layerLoRef: M,
|
|
810
|
+
layerHiRef: B,
|
|
811
|
+
lineWidthRef: ee,
|
|
812
|
+
downgradeRef: L,
|
|
813
|
+
settings: te,
|
|
814
|
+
canvasMode: I,
|
|
815
|
+
downgradeOffer: A,
|
|
816
|
+
runSlice: u,
|
|
817
|
+
ensurePlateToolpaths: _,
|
|
818
|
+
buildPlateToolpath: G,
|
|
819
|
+
applyViewColors: K,
|
|
820
|
+
disposePlateToolpath: h,
|
|
821
|
+
setStats: E,
|
|
822
|
+
setOverBed: k,
|
|
823
|
+
setLayerCount: j,
|
|
824
|
+
setSegCount: f,
|
|
825
|
+
setColorRange: g,
|
|
826
|
+
setRoleLegend: y,
|
|
827
|
+
setGcodeUrl: v,
|
|
828
|
+
setLayerLo: D,
|
|
829
|
+
setLayerHi: W,
|
|
830
|
+
setCanvasMode: oe,
|
|
831
|
+
setSlicedPlateCount: ge,
|
|
832
|
+
setSliceMenu: de,
|
|
833
|
+
setError: Y,
|
|
834
|
+
setSliceNotice: C,
|
|
835
|
+
setDowngradeOffer: pe,
|
|
836
|
+
setSlicing: je,
|
|
837
|
+
setProgress: Ce,
|
|
838
|
+
setPlateCount: ye,
|
|
839
|
+
setSelectedPlate: Re
|
|
840
|
+
} = n;
|
|
841
|
+
function be(Z) {
|
|
842
|
+
var ae;
|
|
843
|
+
_();
|
|
844
|
+
const q = T.current;
|
|
845
|
+
q && q.setLayerRange(0, 1e9);
|
|
846
|
+
const z = m.current[Z];
|
|
847
|
+
if (!z || z.error || !z.layers || !z.layers.length) {
|
|
848
|
+
b.current = null, T.current = null, P.current = null, E(null), k(!1), j(0), f(0), g(null), y([]), v((J) => (J && URL.revokeObjectURL(J), ""));
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
b.current = z.layers;
|
|
852
|
+
const ie = z.layers.length;
|
|
853
|
+
M.current = 0, B.current = ie - 1, D(0), W(ie - 1);
|
|
854
|
+
const we = w.current[Z], se = we && we.layers === z.layers ? we : G(Z, z.layers);
|
|
855
|
+
se && (T.current = se.ctl, P.current = se.seg, se.ctl.setLayerRange(0, ie - 1), K(), f(se.seg.nSeg), y(It(se.seg.typeLengths))), (ae = a.current) == null || ae.onSliced(), oe("preview"), E({
|
|
856
|
+
layers: z.stats.layers,
|
|
857
|
+
segments: z.stats.path_segments,
|
|
858
|
+
filament: z.stats.filament_mm,
|
|
859
|
+
timeSec: z.stats.time_estimate,
|
|
860
|
+
engine: z.stats.time_engine,
|
|
861
|
+
limits: z.stats.machine_limits
|
|
862
|
+
}), k(!!z.stats.over_bed), j(ie), v((J) => (J && URL.revokeObjectURL(J), URL.createObjectURL(new Blob([z.gcode], { type: "text/plain" }))));
|
|
863
|
+
}
|
|
864
|
+
function Se(Z, q) {
|
|
865
|
+
const z = URL.createObjectURL(new Blob([Z], { type: "text/plain" })), ie = document.createElement("a");
|
|
866
|
+
ie.href = z, ie.download = q, ie.style.display = "none", document.body.appendChild(ie), ie.click(), setTimeout(() => {
|
|
867
|
+
ie.remove(), URL.revokeObjectURL(z);
|
|
676
868
|
}, 4e3);
|
|
677
869
|
}
|
|
678
|
-
const
|
|
679
|
-
function
|
|
680
|
-
|
|
870
|
+
const i = (Z) => new Promise((q) => setTimeout(q, Z));
|
|
871
|
+
function S() {
|
|
872
|
+
ge(Object.values(m.current).filter((Z) => Z && !Z.error && Z.gcode).length);
|
|
681
873
|
}
|
|
682
|
-
async function
|
|
683
|
-
|
|
684
|
-
const
|
|
685
|
-
if (!
|
|
686
|
-
|
|
874
|
+
async function V() {
|
|
875
|
+
de(!1);
|
|
876
|
+
const Z = Object.entries(m.current).filter(([, q]) => q && !q.error && q.gcode).sort((q, z) => Number(q[0]) - Number(z[0]));
|
|
877
|
+
if (!Z.length) {
|
|
878
|
+
Y("No slice results to export — slice first");
|
|
687
879
|
return;
|
|
688
880
|
}
|
|
689
|
-
for (const [
|
|
690
|
-
|
|
691
|
-
|
|
881
|
+
for (const [q, z] of Z)
|
|
882
|
+
Se(z.gcode, `plate_${Number(q) + 1}.gcode`), await i(350);
|
|
883
|
+
C(`Exported G-code for ${Z.length} plate(s)`);
|
|
692
884
|
}
|
|
693
|
-
async function
|
|
694
|
-
var
|
|
695
|
-
|
|
696
|
-
const
|
|
697
|
-
if (
|
|
698
|
-
|
|
699
|
-
let
|
|
700
|
-
const
|
|
701
|
-
for (let
|
|
702
|
-
const
|
|
703
|
-
if (
|
|
704
|
-
|
|
885
|
+
async function p(Z = "current") {
|
|
886
|
+
var z, ie;
|
|
887
|
+
de(!1), Y(""), C(""), pe(null);
|
|
888
|
+
const q = c.current;
|
|
889
|
+
if (ee.current = xt(te).line_width, Z === "all") {
|
|
890
|
+
je(!0), Ce(0);
|
|
891
|
+
let we = 0, se = !1, ae = !1;
|
|
892
|
+
const J = [];
|
|
893
|
+
for (let ce = 0; ce < l.current; ce++) {
|
|
894
|
+
const ke = (z = a.current) == null ? void 0 : z.buildMergedSTL(ce);
|
|
895
|
+
if (ke) {
|
|
896
|
+
d.current[ce] = { offX: ke.offX, offZ: ke.offZ };
|
|
705
897
|
try {
|
|
706
|
-
const { r:
|
|
707
|
-
|
|
898
|
+
const { r: ze, economy: Fe, classicWalls: qe } = await u(ke);
|
|
899
|
+
m.current[ce] = ze, S(), we++, Fe && (se = !0), qe && (ae = !0);
|
|
708
900
|
} catch {
|
|
709
|
-
|
|
901
|
+
J.push(ce + 1);
|
|
710
902
|
}
|
|
711
903
|
}
|
|
712
904
|
}
|
|
713
|
-
if (
|
|
714
|
-
|
|
905
|
+
if (je(!1), !we) {
|
|
906
|
+
pe({ scope: "all" }), Y("All plates failed to slice (economy mode included) — try the simplified retry");
|
|
715
907
|
return;
|
|
716
908
|
}
|
|
717
|
-
|
|
909
|
+
J.length ? Y(`Plate ${J.join(", ")} failed — the ${we} finished result(s) are kept (inspect/export from the tabs)`) : (Y(""), pe(null)), se ? C("Memory pressure — some plates finished in economy mode (no preview, G-code is fine)") : ae && C("Arachne wall generation failed (degenerate geometry) — finished with classic walls (G-code is fine)"), be(m.current[q] ? q : Object.keys(m.current).map(Number)[0]);
|
|
718
910
|
} else {
|
|
719
|
-
const
|
|
720
|
-
if (!
|
|
721
|
-
|
|
911
|
+
const we = performance.now(), se = (ie = a.current) == null ? void 0 : ie.buildMergedSTL(q);
|
|
912
|
+
if (!se) {
|
|
913
|
+
Y(`Plate ${q + 1} has no objects`);
|
|
722
914
|
return;
|
|
723
915
|
}
|
|
724
|
-
console.info(`[vp-prof] buildMergedSTL ${(performance.now() -
|
|
916
|
+
console.info(`[vp-prof] buildMergedSTL ${(performance.now() - we).toFixed(0)}ms (${(se.buf.byteLength / 1048576).toFixed(1)}MB)`), d.current[q] = { offX: se.offX, offZ: se.offZ }, je(!0), Ce(0);
|
|
725
917
|
try {
|
|
726
|
-
const { r:
|
|
727
|
-
|
|
728
|
-
} catch (
|
|
729
|
-
|
|
918
|
+
const { r: ae, economy: J, classicWalls: ce, params: ke } = await u(se);
|
|
919
|
+
ae != null && ae.stats && console.info(`[vp-prof] kernel stages p1=${(ae.stats.t_pass1_ms / 1e3).toFixed(1)}s surf=${(ae.stats.t_surface_ms / 1e3).toFixed(1)}s sup=${(ae.stats.t_support_ms / 1e3).toFixed(1)}s emit=${(ae.stats.t_emit_ms / 1e3).toFixed(1)}s reuse=${ke.reuse_stages}`), m.current[q] = ae, S(), je(!1), be(q), Y(""), pe(null), J ? C("Memory pressure — finished in economy mode (no preview, G-code can still be downloaded)") : ce && C("Arachne wall generation failed (degenerate geometry) — finished with classic walls (G-code is fine)");
|
|
920
|
+
} catch (ae) {
|
|
921
|
+
if (je(!1), String((ae == null ? void 0 : ae.message) || ae).includes("canceled")) {
|
|
922
|
+
C("Slice canceled");
|
|
923
|
+
return;
|
|
924
|
+
}
|
|
925
|
+
pe({ scope: "current" }), Y("Slice failed (economy mode failed too): " + ae.message);
|
|
730
926
|
}
|
|
731
927
|
}
|
|
732
928
|
}
|
|
733
|
-
async function
|
|
734
|
-
const
|
|
735
|
-
if (
|
|
736
|
-
|
|
929
|
+
async function O() {
|
|
930
|
+
const Z = A;
|
|
931
|
+
if (pe(null), !!Z) {
|
|
932
|
+
L.current = !0;
|
|
737
933
|
try {
|
|
738
|
-
await
|
|
934
|
+
await p(Z.scope);
|
|
739
935
|
} finally {
|
|
740
|
-
|
|
936
|
+
L.current = !1;
|
|
741
937
|
}
|
|
742
938
|
}
|
|
743
939
|
}
|
|
744
|
-
function
|
|
745
|
-
|
|
940
|
+
function ue() {
|
|
941
|
+
ye((Z) => Math.min(Vt, Z + 1));
|
|
746
942
|
}
|
|
747
|
-
function
|
|
748
|
-
|
|
749
|
-
if (
|
|
750
|
-
const
|
|
751
|
-
return delete
|
|
943
|
+
function ve() {
|
|
944
|
+
ye((Z) => {
|
|
945
|
+
if (Z <= 1) return Z;
|
|
946
|
+
const q = Z - 1;
|
|
947
|
+
return delete m.current[q], h(q), S(), c.current >= q && Ee(q - 1), q;
|
|
752
948
|
});
|
|
753
949
|
}
|
|
754
|
-
function
|
|
755
|
-
|
|
756
|
-
}
|
|
757
|
-
function vn(e, t) {
|
|
758
|
-
if (!(e > 0) || !(t > 0)) return;
|
|
759
|
-
const r = gt(L, "printable_area"), a = Array.isArray(r) && r.length >= 3, l = a ? Math.min(...r.map((s) => s[0])) : 0, d = a ? Math.min(...r.map((s) => s[1])) : 0;
|
|
760
|
-
$((s) => ({ ...s, printable_area: [[l, d], [l + e, d], [l + e, d + t], [l, d + t]] }));
|
|
950
|
+
function Ee(Z) {
|
|
951
|
+
c.current = Z, Re(Z), r.current = 0, I === "preview" && be(Z);
|
|
761
952
|
}
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
953
|
+
return { showPlateResult: be, refreshSlicedCount: S, exportAllGcode: V, onSlice: p, retryDowngrade: O, addPlate: ue, deletePlate: ve, selectPlate: Ee };
|
|
954
|
+
}
|
|
955
|
+
function Nr(n) {
|
|
956
|
+
const {
|
|
957
|
+
apiRef: a,
|
|
958
|
+
objectsRef: c,
|
|
959
|
+
layersDataRef: l,
|
|
960
|
+
segDataRef: r,
|
|
961
|
+
plateResultsRef: m,
|
|
962
|
+
plateOffsetsRef: d,
|
|
963
|
+
clearToolpaths: w,
|
|
964
|
+
refreshSlicedCount: b,
|
|
965
|
+
dragOver: T,
|
|
966
|
+
setError: P,
|
|
967
|
+
setTriWarn: M,
|
|
968
|
+
setProgress: B,
|
|
969
|
+
setStats: ee,
|
|
970
|
+
setOverBed: L,
|
|
971
|
+
setLayerCount: te,
|
|
972
|
+
setSegCount: I,
|
|
973
|
+
setColorRange: A,
|
|
974
|
+
setSliceNotice: u,
|
|
975
|
+
setDowngradeOffer: _,
|
|
976
|
+
setGcodeUrl: G,
|
|
977
|
+
setCanvasMode: K,
|
|
978
|
+
setObjects: h,
|
|
979
|
+
setDragOver: E
|
|
980
|
+
} = n;
|
|
981
|
+
async function k(D) {
|
|
982
|
+
var de, Y;
|
|
983
|
+
const W = Array.from(D || []).filter((C) => bt.includes(Vn(C.name))), oe = Array.from(D || []).length - W.length;
|
|
984
|
+
if (!W.length) {
|
|
985
|
+
oe && P("Supported formats: STL/OBJ/3MF/AMF/PLY");
|
|
986
|
+
return;
|
|
771
987
|
}
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
tr(e), e && ce(ee.current, ee.current);
|
|
988
|
+
P(""), M(""), B(0), l.current = null, r.current = null, m.current = {}, d.current = {}, w(), b(), ee(null), L(!1), te(0), I(0), A(null), u(""), _(null), G((C) => (C && URL.revokeObjectURL(C), "")), K("prepare"), (de = a.current) == null || de.showObjects();
|
|
989
|
+
let ge = 0;
|
|
990
|
+
for (const C of W)
|
|
991
|
+
try {
|
|
992
|
+
const pe = performance.now(), je = await C.arrayBuffer(), Ce = performance.now(), ye = await Fn(C.name, je), Re = performance.now();
|
|
993
|
+
for (const be of ye)
|
|
994
|
+
(Y = a.current) == null || Y.addObject(be.name, be.modelPos), ge += be.modelPos.length / 9;
|
|
995
|
+
console.info(`[vp-prof] load ${C.name}: read ${(Ce - pe).toFixed(0)}ms, parse ${(Re - Ce).toFixed(0)}ms, scene ${(performance.now() - Re).toFixed(0)}ms`);
|
|
996
|
+
} catch (pe) {
|
|
997
|
+
P(`Failed to load ${C.name}: ${pe && pe.message || pe}`);
|
|
998
|
+
}
|
|
999
|
+
h(c.current.map((C) => ({ id: C.id, name: C.name, extruder: C.extruder, visible: C.visible !== !1 }))), ge > 1e5 && M(`${Math.round(ge).toLocaleString()} triangles — slicing may take a while`);
|
|
785
1000
|
}
|
|
786
|
-
function
|
|
787
|
-
|
|
788
|
-
er(t), vt.current = t, Zt();
|
|
1001
|
+
function j(D) {
|
|
1002
|
+
k(D.target.files), D.target.value = "";
|
|
789
1003
|
}
|
|
790
|
-
function
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
for (const r of Object.values(y.current)) r.ctl.setTravelVisible(t);
|
|
1004
|
+
function f(D) {
|
|
1005
|
+
var W;
|
|
1006
|
+
(W = a.current) == null || W.removeObject(D), h(c.current.map((oe) => ({ id: oe.id, name: oe.name, extruder: oe.extruder, visible: oe.visible !== !1 })));
|
|
794
1007
|
}
|
|
795
|
-
function
|
|
796
|
-
|
|
797
|
-
|
|
1008
|
+
function g(D) {
|
|
1009
|
+
var W;
|
|
1010
|
+
D.preventDefault(), E(!1), k((W = D.dataTransfer) == null ? void 0 : W.files);
|
|
798
1011
|
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
rt(w.current.map((e) => ({ id: e.id, name: e.name, extruder: e.extruder, visible: e.visible !== !1 })));
|
|
1012
|
+
function y(D) {
|
|
1013
|
+
D.preventDefault(), D.dataTransfer && (D.dataTransfer.dropEffect = "copy"), T || E(!0);
|
|
802
1014
|
}
|
|
803
|
-
function
|
|
804
|
-
|
|
805
|
-
var l;
|
|
806
|
-
const a = [...r];
|
|
807
|
-
return a[e] = t, Ae.current = a, (l = c.current) == null || l.recolorObjects(), a;
|
|
808
|
-
});
|
|
1015
|
+
function v(D) {
|
|
1016
|
+
D.currentTarget.contains(D.relatedTarget) || E(!1);
|
|
809
1017
|
}
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
1018
|
+
return { loadFiles: k, onFiles: j, removeObject: f, onDrop: g, onDragOver: y, onDragLeave: v };
|
|
1019
|
+
}
|
|
1020
|
+
function Ar(n) {
|
|
1021
|
+
const {
|
|
1022
|
+
three: a,
|
|
1023
|
+
objectsRef: c,
|
|
1024
|
+
apiRef: l,
|
|
1025
|
+
getWorker: r,
|
|
1026
|
+
selectedPlateRef: m,
|
|
1027
|
+
paintXformRef: d,
|
|
1028
|
+
paintOverlayRef: w,
|
|
1029
|
+
paintModeRef: b,
|
|
1030
|
+
setError: T,
|
|
1031
|
+
setPaintModeState: P,
|
|
1032
|
+
setPaintCounts: M
|
|
1033
|
+
} = n;
|
|
1034
|
+
function B(I, A) {
|
|
1035
|
+
var h, E;
|
|
1036
|
+
const u = a.current;
|
|
1037
|
+
if (!u.objectsGroup) return;
|
|
1038
|
+
const _ = d.current || { cx: 0, cy: 0, minz: 0 }, G = w.current;
|
|
1039
|
+
if (G)
|
|
1040
|
+
for (const k of ["enf", "blk"]) G[k] && (u.objectsGroup.remove(G[k]), G[k].geometry.dispose(), G[k].material.dispose());
|
|
1041
|
+
const K = (k, j) => {
|
|
1042
|
+
if (!k || k.length < 9) return null;
|
|
1043
|
+
const f = new Float32Array(k.length);
|
|
1044
|
+
for (let v = 0; v < k.length; v += 3) {
|
|
1045
|
+
const D = k[v], W = k[v + 1], oe = k[v + 2];
|
|
1046
|
+
f[v] = D + _.cx, f[v + 1] = oe + _.minz, f[v + 2] = -(W + _.cy);
|
|
1047
|
+
}
|
|
1048
|
+
const g = new N.BufferGeometry();
|
|
1049
|
+
g.setAttribute("position", new N.Float32BufferAttribute(f, 3)), g.computeVertexNormals();
|
|
1050
|
+
const y = new N.Mesh(g, new N.MeshBasicMaterial({ color: j, transparent: !0, opacity: 0.55, side: N.DoubleSide, depthTest: !1 }));
|
|
1051
|
+
return y.renderOrder = 999, u.objectsGroup.add(y), y;
|
|
1052
|
+
};
|
|
1053
|
+
w.current = { enf: K(I, 2845951), blk: K(A, 14826299) }, (E = (h = a.current).invalidate) == null || E.call(h);
|
|
816
1054
|
}
|
|
817
|
-
function
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
const t = e.slice(0, -1);
|
|
822
|
-
return Ae.current = t, w.current.forEach((a) => {
|
|
823
|
-
var l;
|
|
824
|
-
(a.extruder || 1) > t.length && ((l = c.current) == null || l.setObjectExtruder(a.id, t.length));
|
|
825
|
-
}), (r = c.current) == null || r.recolorObjects(), Se(), t;
|
|
826
|
-
});
|
|
1055
|
+
function ee() {
|
|
1056
|
+
const I = a.current, A = w.current;
|
|
1057
|
+
if (A && I.objectsGroup) for (const u of ["enf", "blk"]) A[u] && (I.objectsGroup.remove(A[u]), A[u].geometry.dispose(), A[u].material.dispose());
|
|
1058
|
+
w.current = null;
|
|
827
1059
|
}
|
|
828
|
-
function
|
|
829
|
-
var
|
|
830
|
-
|
|
831
|
-
|
|
1060
|
+
function L(I) {
|
|
1061
|
+
var A, u, _;
|
|
1062
|
+
if (I !== "off" && c.current.length === 0) {
|
|
1063
|
+
T("Upload an STL first");
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1066
|
+
if (I !== "off") {
|
|
1067
|
+
const G = (A = l.current) == null ? void 0 : A.buildMergedSTL(m.current);
|
|
1068
|
+
if (!G) return;
|
|
1069
|
+
d.current = { cx: G.offX, cy: -G.offZ, minz: 0 }, (u = l.current) == null || u.detachTransform(), r().postMessage({ cmd: "prepare", stl: G.buf });
|
|
1070
|
+
}
|
|
1071
|
+
b.current = I, P(I), (_ = l.current) == null || _.refreshCursor();
|
|
832
1072
|
}
|
|
833
|
-
function
|
|
834
|
-
|
|
1073
|
+
function te() {
|
|
1074
|
+
r().postMessage({ cmd: "clear" }), ee(), M({ enf: 0, blk: 0 });
|
|
835
1075
|
}
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
{ id: "boolean", icon: pa, label: "불리언", tip: "메시 불리언 — 두 오브젝트의 합/차/교집합. 미구현(CGAL 불리언 이식 필요)" },
|
|
856
|
-
{ id: "negative", icon: va, label: "음각 파트", tip: "음각·모디파이어 파트 추가 — 한 오브젝트 안에 성질이 다른 파트를 넣음. 미구현(파트 개념 부재)" },
|
|
857
|
-
{ sep: !0 },
|
|
858
|
-
{ id: "seam", icon: ja, label: "심 페인팅", tip: "심 페인팅 — 레이어 이음매 위치를 브러시로 지정. 미구현(커널 심 배선 필요)" },
|
|
859
|
-
{ id: "mmu", icon: ga, label: "컬러 페인팅", tip: "컬러 페인팅 — 멀티머티리얼 색을 면 단위로 지정. 미구현(MMU 페인트 코덱 배선 필요)" },
|
|
860
|
-
{ id: "text", icon: Na, label: "텍스트", tip: "텍스트·SVG 각인 — 모델 표면에 문자/도형을 새김. 미구현(폰트 래스터화 필요)" },
|
|
861
|
-
{ id: "measure", icon: ha, label: "측정", tip: "측정 — 두 지점/면 사이 거리·각도 측정. 미구현" },
|
|
862
|
-
{ id: "varlayer", icon: _a, label: "가변 레이어", tip: "가변 레이어 높이 — 구간별로 레이어 높이를 다르게. 미구현(커널 가변 z 미지원)" }
|
|
863
|
-
];
|
|
864
|
-
function It() {
|
|
865
|
-
var r, a, l;
|
|
866
|
-
const e = (r = c.current) == null ? void 0 : r.selectedObjectId();
|
|
867
|
-
if (!e) {
|
|
868
|
-
_("먼저 복제할 오브젝트를 선택하세요");
|
|
1076
|
+
return { rebuildPaintOverlay: B, clearPaintOverlay: ee, setPaintMode: L, clearPaint: te };
|
|
1077
|
+
}
|
|
1078
|
+
function _r(n) {
|
|
1079
|
+
const {
|
|
1080
|
+
apiRef: a,
|
|
1081
|
+
objectsRef: c,
|
|
1082
|
+
clipboardRef: l,
|
|
1083
|
+
paintModeRef: r,
|
|
1084
|
+
setPaintMode: m,
|
|
1085
|
+
removeObject: d,
|
|
1086
|
+
refreshObjects: w,
|
|
1087
|
+
setError: b,
|
|
1088
|
+
setSliceNotice: T
|
|
1089
|
+
} = n;
|
|
1090
|
+
function P() {
|
|
1091
|
+
var _, G, K;
|
|
1092
|
+
const A = (_ = a.current) == null ? void 0 : _.selectedObjectId();
|
|
1093
|
+
if (!A) {
|
|
1094
|
+
b("Select an object to duplicate first");
|
|
869
1095
|
return;
|
|
870
1096
|
}
|
|
871
|
-
const
|
|
872
|
-
|
|
1097
|
+
const u = (G = a.current) == null ? void 0 : G.getSnapshot(A);
|
|
1098
|
+
u && ((K = a.current) == null || K.spawnSnapshot(u), w(), b(""));
|
|
873
1099
|
}
|
|
874
|
-
function
|
|
875
|
-
var
|
|
876
|
-
const
|
|
877
|
-
if (!
|
|
878
|
-
|
|
1100
|
+
function M() {
|
|
1101
|
+
var u, _;
|
|
1102
|
+
const A = (u = a.current) == null ? void 0 : u.selectedObjectId();
|
|
1103
|
+
if (!A) {
|
|
1104
|
+
b("Select an object to copy first");
|
|
879
1105
|
return;
|
|
880
1106
|
}
|
|
881
|
-
|
|
1107
|
+
l.current = (_ = a.current) == null ? void 0 : _.getSnapshot(A), b(""), T("Object copied (paste with Ctrl+V)");
|
|
882
1108
|
}
|
|
883
|
-
function
|
|
884
|
-
var
|
|
885
|
-
|
|
1109
|
+
function B() {
|
|
1110
|
+
var A;
|
|
1111
|
+
l.current && ((A = a.current) == null || A.spawnSnapshot(l.current), w());
|
|
886
1112
|
}
|
|
887
|
-
function
|
|
888
|
-
var
|
|
889
|
-
const
|
|
890
|
-
if (!
|
|
891
|
-
|
|
1113
|
+
function ee() {
|
|
1114
|
+
var u;
|
|
1115
|
+
const A = (u = a.current) == null ? void 0 : u.selectedObjectId();
|
|
1116
|
+
if (!A) {
|
|
1117
|
+
b("Select an object to delete first");
|
|
892
1118
|
return;
|
|
893
1119
|
}
|
|
894
|
-
|
|
1120
|
+
d(A), b("");
|
|
895
1121
|
}
|
|
896
|
-
function
|
|
897
|
-
var
|
|
898
|
-
const
|
|
899
|
-
if (
|
|
900
|
-
for (const
|
|
901
|
-
|
|
1122
|
+
function L() {
|
|
1123
|
+
var u;
|
|
1124
|
+
const A = c.current.map((_) => _.id);
|
|
1125
|
+
if (A.length) {
|
|
1126
|
+
for (const _ of A) (u = a.current) == null || u.removeObject(_);
|
|
1127
|
+
w(), T(`Deleted all ${A.length} object(s)`);
|
|
902
1128
|
}
|
|
903
1129
|
}
|
|
904
|
-
function
|
|
905
|
-
var
|
|
906
|
-
const
|
|
907
|
-
if (!
|
|
908
|
-
|
|
1130
|
+
function te() {
|
|
1131
|
+
var K, h;
|
|
1132
|
+
const A = (K = a.current) == null ? void 0 : K.selectedObjectId();
|
|
1133
|
+
if (!A) {
|
|
1134
|
+
b("Select an object to split first");
|
|
909
1135
|
return;
|
|
910
1136
|
}
|
|
911
|
-
const
|
|
912
|
-
if (!
|
|
913
|
-
let
|
|
1137
|
+
const u = (h = a.current) == null ? void 0 : h.getSnapshot(A);
|
|
1138
|
+
if (!u) return;
|
|
1139
|
+
let _;
|
|
914
1140
|
try {
|
|
915
|
-
|
|
916
|
-
} catch (
|
|
917
|
-
|
|
1141
|
+
_ = Gn(u.localPos);
|
|
1142
|
+
} catch (E) {
|
|
1143
|
+
b("Split failed: " + ((E == null ? void 0 : E.message) || E));
|
|
918
1144
|
return;
|
|
919
1145
|
}
|
|
920
|
-
if (!
|
|
921
|
-
|
|
1146
|
+
if (!_ || _.length < 2) {
|
|
1147
|
+
b("No separate parts to split — this is a single connected mesh");
|
|
922
1148
|
return;
|
|
923
1149
|
}
|
|
924
|
-
const
|
|
925
|
-
|
|
926
|
-
var
|
|
927
|
-
return (
|
|
928
|
-
{ name: `${
|
|
1150
|
+
const G = String(u.name || "object").replace(/\.[^.]+$/, "");
|
|
1151
|
+
d(A), _.forEach((E, k) => {
|
|
1152
|
+
var j;
|
|
1153
|
+
return (j = a.current) == null ? void 0 : j.spawnSnapshot(
|
|
1154
|
+
{ name: `${G}_${k + 1}`, localPos: E, rot: u.rot, scale: u.scale, pos: u.pos },
|
|
929
1155
|
!0
|
|
930
1156
|
);
|
|
931
|
-
}),
|
|
1157
|
+
}), w(), b(""), T(`Split into ${_.length} objects`);
|
|
932
1158
|
}
|
|
933
|
-
function
|
|
934
|
-
var
|
|
935
|
-
|
|
1159
|
+
function I(A) {
|
|
1160
|
+
var u;
|
|
1161
|
+
r.current !== "off" && m("off"), (u = a.current) == null || u.setMode(A);
|
|
936
1162
|
}
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
if (r === "ArrowUp") {
|
|
951
|
-
s();
|
|
952
|
-
const Z = ee.current + j;
|
|
953
|
-
ce(ke ? Z : ue.current, Z);
|
|
954
|
-
} else if (r === "ArrowDown") {
|
|
955
|
-
s();
|
|
956
|
-
const Z = ee.current - j;
|
|
957
|
-
ce(ke ? Z : ue.current, Z);
|
|
958
|
-
} else a === "l" ? (s(), wn()) : a === "t" ? (s(), yn({ target: { checked: !xt.current } })) : a === "z" ? (s(), (b = c.current) == null || b.frame()) : a === "b" ? (s(), (u = c.current) == null || u.frameBed()) : r === "Escape" && (s(), _e("prepare"));
|
|
959
|
-
return;
|
|
960
|
-
}
|
|
961
|
-
if (a === "m" || a === "g")
|
|
962
|
-
s(), $t("translate");
|
|
963
|
-
else if (a === "r")
|
|
964
|
-
s(), $t("rotate");
|
|
965
|
-
else if (a === "s")
|
|
966
|
-
s(), $t("scale");
|
|
967
|
-
else if (a === "z")
|
|
968
|
-
s(), (P = c.current) == null || P.frame();
|
|
969
|
-
else if (a === "b")
|
|
970
|
-
s(), (m = c.current) == null || m.frameBed();
|
|
971
|
-
else if (r === "Delete" || r === "Backspace")
|
|
972
|
-
s(), ut();
|
|
973
|
-
else if (r === "Escape")
|
|
974
|
-
s(), q.current !== "off" && re("off"), (h = c.current) == null || h.detachTransform();
|
|
975
|
-
else if (r === "PageUp")
|
|
976
|
-
s(), (I = c.current) == null || I.rotateSelectedY(Math.PI / 4);
|
|
977
|
-
else if (r === "PageDown")
|
|
978
|
-
s(), (T = c.current) == null || T.rotateSelectedY(-Math.PI / 4);
|
|
979
|
-
else if ((Y = r.startsWith) != null && Y.call(r, "Arrow")) {
|
|
980
|
-
s();
|
|
981
|
-
const j = e.shiftKey ? 1 : 10;
|
|
982
|
-
(M = c.current) == null || M.nudgeSelected(
|
|
983
|
-
r === "ArrowLeft" ? -j : r === "ArrowRight" ? j : 0,
|
|
984
|
-
r === "ArrowUp" ? -j : r === "ArrowDown" ? j : 0
|
|
985
|
-
);
|
|
986
|
-
} else r === "?" && (s(), en((j) => !j));
|
|
987
|
-
};
|
|
988
|
-
const Ur = X.nozzle_diameter || gt(L, "nozzle_diameter") || "0.4";
|
|
989
|
-
(Cn = (Mn = N.current).invalidate) == null || Cn.call(Mn);
|
|
990
|
-
const En = je > 0 && /* @__PURE__ */ n.createElement("div", { className: "slice-layer", "data-testid": "preview-controls" }, /* @__PURE__ */ n.createElement("label", { className: "view-type-row" }, "뷰 타입", /* @__PURE__ */ n.createElement("select", { value: Qn, onChange: Lr, "data-testid": "view-type-select", title: "툴패스 색을 무엇으로 칠할지 — 피처 종류·속도·레이어 높이·폭·팬·온도" }, Qr.map((e) => /* @__PURE__ */ n.createElement("option", { key: e.key, value: e.key }, e.label)))), /* @__PURE__ */ n.createElement("label", null, "레이어 ", /* @__PURE__ */ n.createElement("b", { "data-testid": "layer-range" }, ke ? At + 1 : `${nn + 1}..${At + 1}`), " / ", je, /* @__PURE__ */ n.createElement("span", { className: "muted" }, " (", Wn.toLocaleString(), " 세그먼트)")), /* @__PURE__ */ n.createElement("div", { className: "dual-slider" }, /* @__PURE__ */ n.createElement("input", { type: "range", min: "0", max: Math.max(0, je - 1), value: nn, onChange: zr, "data-testid": "layer-lo", title: "표시할 최하단 레이어 (↓/↑ 로도 조절)" }), /* @__PURE__ */ n.createElement("input", { type: "range", min: "0", max: Math.max(0, je - 1), value: At, onChange: Rr, "data-testid": "layer-hi", title: "표시할 최상단 레이어 (↓/↑, Shift 로 10단계)" })), /* @__PURE__ */ n.createElement("div", { className: "layer-ctl" }, /* @__PURE__ */ n.createElement("button", { className: ke ? "on" : "", onClick: wn, "data-testid": "single-layer-btn", title: "선택한 한 층만 보기 (L)" }, "단일 레이어"), /* @__PURE__ */ n.createElement("label", { className: "slice-travel" }, /* @__PURE__ */ n.createElement("input", { type: "checkbox", checked: rr, onChange: yn, "data-testid": "travel-toggle", title: "압출 없이 이동하는 경로를 회색 선으로 표시 (T)" }), " 트래블")), he && he.cont ? /* @__PURE__ */ n.createElement("div", { className: "grad-legend", "data-testid": "view-legend" }, /* @__PURE__ */ n.createElement("div", { className: "grad-title" }, he.label, " ", /* @__PURE__ */ n.createElement("span", { className: "muted" }, he.unit)), /* @__PURE__ */ n.createElement("div", { className: "grad-bar", "data-testid": "gradient-bar", style: { background: `linear-gradient(to right, ${ea.map((e) => `rgb(${Math.round(e[0] * 255)},${Math.round(e[1] * 255)},${Math.round(e[2] * 255)})`).join(",")})` } }), /* @__PURE__ */ n.createElement("div", { className: "grad-minmax" }, /* @__PURE__ */ n.createElement("span", { "data-testid": "grad-min" }, he.min.toFixed(he.unit === "mm" ? 2 : 0)), /* @__PURE__ */ n.createElement("span", { "data-testid": "grad-max" }, he.max.toFixed(he.unit === "mm" ? 2 : 0)))) : /* @__PURE__ */ n.createElement("div", { className: "role-legend", "data-testid": "view-legend" }, nr.map((e) => /* @__PURE__ */ n.createElement("span", { key: e.type, className: "role-item" }, /* @__PURE__ */ n.createElement("i", { style: { background: `rgb(${Math.round(e.color[0] * 255)},${Math.round(e.color[1] * 255)},${Math.round(e.color[2] * 255)})` } }), e.label, " ", /* @__PURE__ */ n.createElement("b", null, e.pct.toFixed(0), "%"))))), Dr = be && /* @__PURE__ */ n.createElement(n.Fragment, null, /* @__PURE__ */ n.createElement("div", null, /* @__PURE__ */ n.createElement("b", null, be.layers), " 레이어 · ", /* @__PURE__ */ n.createElement("b", null, be.segments), " 세그먼트"), /* @__PURE__ */ n.createElement("div", null, "필라멘트 ", /* @__PURE__ */ n.createElement("b", null, be.filament.toFixed(1)), " mm"), typeof be.timeSec == "number" && be.timeSec > 0 && (() => {
|
|
991
|
-
const e = Math.round(be.timeSec), t = `${Math.floor(e / 3600)}h ${String(Math.floor(e % 3600 / 60)).padStart(2, "0")}m ${String(e % 60).padStart(2, "0")}s`;
|
|
992
|
-
return /* @__PURE__ */ n.createElement("div", { "data-testid": "print-time" }, "⏱ 예상 출력 ", /* @__PURE__ */ n.createElement("b", null, t));
|
|
993
|
-
})(), qn && /* @__PURE__ */ n.createElement("div", { className: "slice-warn", "data-testid": "over-bed" }, "⚠ 모델이 베드를 벗어남"));
|
|
994
|
-
return /* @__PURE__ */ n.createElement(sa, { css: ia }, /* @__PURE__ */ n.createElement("div", { className: "app-shell" }, /* @__PURE__ */ n.createElement("input", { ref: Te, type: "file", accept: ".stl,.obj,.3mf,.amf,.ply", multiple: !0, onChange: fr, title: "STL·OBJ·3MF·AMF·PLY (여러 개 선택 가능)", "data-testid": "stl-input", style: { display: "none" } }), /* @__PURE__ */ n.createElement("header", { className: "topbar" }, /* @__PURE__ */ n.createElement("div", { className: "tb-left" }, /* @__PURE__ */ n.createElement("span", { className: "tb-logo" }, /* @__PURE__ */ n.createElement("b", null, "Three"), "Slicer ", /* @__PURE__ */ n.createElement("span", { className: "tb-re" }, "RE")), /* @__PURE__ */ n.createElement("button", { className: "tb-btn", onClick: () => {
|
|
995
|
-
var e;
|
|
996
|
-
return (e = Te.current) == null ? void 0 : e.click();
|
|
997
|
-
}, title: "모델 파일 열기 — 기존 오브젝트는 모두 지워짐", "data-testid": "open-file" }, /* @__PURE__ */ n.createElement("img", { src: ya, alt: "" }), /* @__PURE__ */ n.createElement("span", null, "열기"))), W && /* @__PURE__ */ n.createElement("div", { className: "tb-tabs", role: "tablist", "aria-label": "캔버스 모드" }, /* @__PURE__ */ n.createElement("button", { role: "tab", className: G === "prepare" ? "on" : "", onClick: () => _e("prepare"), "data-testid": "mode-prepare", title: "모델 배치·변형·서포트 페인팅" }, "Prepare"), /* @__PURE__ */ n.createElement("button", { role: "tab", className: G === "preview" ? "on" : "", onClick: () => _e("preview"), disabled: je === 0, "data-testid": "mode-preview", title: "슬라이스된 툴패스 미리보기 (슬라이스 후 활성화)" }, "Preview")), /* @__PURE__ */ n.createElement("div", { className: "tb-right" }, /* @__PURE__ */ n.createElement("button", { className: "tb-icon", disabled: !0, title: "실행 취소 — 미구현(작업 이력 스택 필요)" }, "↶"), /* @__PURE__ */ n.createElement("button", { className: "tb-icon", disabled: !0, title: "다시 실행 — 미구현(작업 이력 스택 필요)" }, "↷"))), /* @__PURE__ */ n.createElement("div", { className: "app-body" }, W && G === "prepare" && /* @__PURE__ */ n.createElement("nav", { className: "left-rail", role: "toolbar", "aria-label": "기즈모 도구" }, /* @__PURE__ */ n.createElement("button", { className: Et === "translate" && ge === "off" ? "on" : "", onClick: () => {
|
|
998
|
-
var e;
|
|
999
|
-
re("off"), (e = c.current) == null || e.setMode("translate");
|
|
1000
|
-
}, title: "오브젝트 이동 — 기즈모 축을 끌거나 방향키로 10mm(Shift 1mm) 이동 (M/G)", "data-testid": "gizmo-move" }, /* @__PURE__ */ n.createElement("img", { src: xa, alt: "이동" })), /* @__PURE__ */ n.createElement("button", { className: Et === "rotate" && ge === "off" ? "on" : "", onClick: () => {
|
|
1001
|
-
var e;
|
|
1002
|
-
re("off"), (e = c.current) == null || e.setMode("rotate");
|
|
1003
|
-
}, title: "오브젝트 회전 — PageUp/PageDown 으로 45° 단위 회전 (R)", "data-testid": "gizmo-rotate" }, /* @__PURE__ */ n.createElement("img", { src: Ma, alt: "회전" })), /* @__PURE__ */ n.createElement("button", { className: Et === "scale" && ge === "off" ? "on" : "", onClick: () => {
|
|
1004
|
-
var e;
|
|
1005
|
-
re("off"), (e = c.current) == null || e.setMode("scale");
|
|
1006
|
-
}, title: "오브젝트 크기 조절 (S)", "data-testid": "gizmo-scale" }, /* @__PURE__ */ n.createElement("img", { src: Ca, alt: "스케일" })), /* @__PURE__ */ n.createElement("div", { className: "rail-sep" }), /* @__PURE__ */ n.createElement("button", { className: ge !== "off" ? "on" : "", onClick: Fr, title: "브러시로 면을 칠해 서포트를 강제하거나 차단 — 휠로 브러시 크기 조절", "data-testid": "gizmo-paint" }, /* @__PURE__ */ n.createElement("img", { src: Ea, alt: "서포트 페인팅" }))), /* @__PURE__ */ n.createElement("div", { className: "viewport-col" }, /* @__PURE__ */ n.createElement(
|
|
1007
|
-
"div",
|
|
1008
|
-
{
|
|
1009
|
-
className: (W ? "vp-canvas" : "vp-canvas fail") + (Rt ? " drag-over" : ""),
|
|
1010
|
-
ref: J,
|
|
1011
|
-
onDrop: br,
|
|
1012
|
-
onDragOver: hr,
|
|
1013
|
-
onDragLeave: gr,
|
|
1014
|
-
"data-testid": "drop-zone"
|
|
1015
|
-
},
|
|
1016
|
-
!W && /* @__PURE__ */ n.createElement("div", { className: "vp-fallback" }, "⚠ ", Wt),
|
|
1017
|
-
W && Ce.length === 0 && G !== "preview" && /* @__PURE__ */ n.createElement("div", { className: "empty-hint", "data-testid": "empty-hint" }, /* @__PURE__ */ n.createElement("div", { className: "eh-icon" }, "📦"), /* @__PURE__ */ n.createElement("div", { className: "eh-title" }, "파일을 드래그하거나 선택하세요"), /* @__PURE__ */ n.createElement("div", { className: "eh-sub" }, "STL · OBJ · 3MF · AMF · PLY"), /* @__PURE__ */ n.createElement("button", { className: "eh-btn", onClick: () => {
|
|
1018
|
-
var e;
|
|
1019
|
-
return (e = Te.current) == null ? void 0 : e.click();
|
|
1020
|
-
}, "data-testid": "empty-pick", title: "STL·OBJ·3MF·AMF·PLY 파일 선택 (여러 개 가능)" }, "파일 선택")),
|
|
1021
|
-
Rt && /* @__PURE__ */ n.createElement("div", { className: "drop-overlay", "data-testid": "drop-overlay" }, "여기에 놓기 (STL/OBJ/3MF/AMF/PLY)"),
|
|
1022
|
-
st && /* @__PURE__ */ n.createElement(n.Fragment, null, /* @__PURE__ */ n.createElement("div", { className: "ctx-scrim", onPointerDown: () => D(null), onContextMenu: (e) => {
|
|
1023
|
-
e.preventDefault(), D(null);
|
|
1024
|
-
} }), /* @__PURE__ */ n.createElement("div", { className: "ctx-menu", style: { left: st.x, top: st.y }, "data-testid": "ctx-menu" }, st.onObject ? /* @__PURE__ */ n.createElement(n.Fragment, null, /* @__PURE__ */ n.createElement("button", { onClick: () => {
|
|
1025
|
-
D(null), It();
|
|
1026
|
-
}, "data-testid": "ctx-duplicate", title: "선택 오브젝트를 같은 크기·회전으로 복제해 옆에 배치" }, "복제 ", /* @__PURE__ */ n.createElement("span", { className: "ctx-key" }, "Ctrl+K")), /* @__PURE__ */ n.createElement("button", { onClick: () => {
|
|
1027
|
-
D(null), Ft();
|
|
1028
|
-
}, "data-testid": "ctx-copy", title: "선택 오브젝트를 버퍼에 복사 (붙여넣기로 추가)" }, "복사 ", /* @__PURE__ */ n.createElement("span", { className: "ctx-key" }, "Ctrl+C")), /* @__PURE__ */ n.createElement("button", { onClick: () => {
|
|
1029
|
-
D(null), Vt();
|
|
1030
|
-
}, "data-testid": "ctx-split", title: "객체로 분리 — 서로 떨어진 부분(연결 성분)마다 독립 오브젝트로 나눔. 파트로 분리는 미구현(파트 개념 부재)" }, "분리"), /* @__PURE__ */ n.createElement("button", { onClick: () => {
|
|
1031
|
-
var e;
|
|
1032
|
-
D(null), (e = c.current) == null || e.placeOnBed();
|
|
1033
|
-
}, "data-testid": "ctx-seat", title: "모든 오브젝트를 베드 바닥(Z=0)에 붙임" }, "바닥에 놓기"), /* @__PURE__ */ n.createElement("hr", null), /* @__PURE__ */ n.createElement("button", { className: "danger", onClick: () => {
|
|
1034
|
-
D(null), ut();
|
|
1035
|
-
}, "data-testid": "ctx-delete", title: "선택 오브젝트를 씬에서 제거" }, "삭제 ", /* @__PURE__ */ n.createElement("span", { className: "ctx-key" }, "Del"))) : /* @__PURE__ */ n.createElement(n.Fragment, null, /* @__PURE__ */ n.createElement("button", { onClick: () => {
|
|
1036
|
-
var e;
|
|
1037
|
-
D(null), (e = Te.current) == null || e.click();
|
|
1038
|
-
}, "data-testid": "ctx-open", title: "모델 파일을 열어 현재 플레이트에 추가" }, "모델 열기…"), /* @__PURE__ */ n.createElement("button", { disabled: !Ye.current, onClick: () => {
|
|
1039
|
-
D(null), kn();
|
|
1040
|
-
}, "data-testid": "ctx-paste", title: "복사해 둔 오브젝트를 현재 플레이트에 추가" }, "붙여넣기 ", /* @__PURE__ */ n.createElement("span", { className: "ctx-key" }, "Ctrl+V")), /* @__PURE__ */ n.createElement("hr", null), /* @__PURE__ */ n.createElement("button", { onClick: () => {
|
|
1041
|
-
var e;
|
|
1042
|
-
D(null), (e = c.current) == null || e.frame();
|
|
1043
|
-
}, "data-testid": "ctx-zoom-all", title: "모든 오브젝트가 보이도록 카메라 맞춤" }, "전체 보기 ", /* @__PURE__ */ n.createElement("span", { className: "ctx-key" }, "Z")), /* @__PURE__ */ n.createElement("button", { onClick: () => {
|
|
1044
|
-
var e;
|
|
1045
|
-
D(null), (e = c.current) == null || e.frameBed();
|
|
1046
|
-
}, "data-testid": "ctx-zoom-bed", title: "선택한 플레이트 전체가 보이도록 카메라 맞춤" }, "베드 보기 ", /* @__PURE__ */ n.createElement("span", { className: "ctx-key" }, "B"))))),
|
|
1047
|
-
Kn && /* @__PURE__ */ n.createElement("div", { className: "help-overlay", "data-testid": "help-overlay", onClick: () => en(!1) }, /* @__PURE__ */ n.createElement("div", { className: "help-card", onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ n.createElement("h3", null, "단축키 ", /* @__PURE__ */ n.createElement("span", { className: "muted" }, "(? 로 닫기)")), /* @__PURE__ */ n.createElement("div", { className: "help-cols" }, /* @__PURE__ */ n.createElement("section", null, /* @__PURE__ */ n.createElement("h4", null, "Prepare"), /* @__PURE__ */ n.createElement("dl", null, /* @__PURE__ */ n.createElement("dt", null, "M / G"), /* @__PURE__ */ n.createElement("dd", null, "이동"), /* @__PURE__ */ n.createElement("dt", null, "R"), /* @__PURE__ */ n.createElement("dd", null, "회전"), /* @__PURE__ */ n.createElement("dt", null, "S"), /* @__PURE__ */ n.createElement("dd", null, "스케일"), /* @__PURE__ */ n.createElement("dt", null, "방향키"), /* @__PURE__ */ n.createElement("dd", null, "10mm 이동 (Shift 1mm)"), /* @__PURE__ */ n.createElement("dt", null, "PageUp/Down"), /* @__PURE__ */ n.createElement("dd", null, "45° 회전"), /* @__PURE__ */ n.createElement("dt", null, "Del"), /* @__PURE__ */ n.createElement("dd", null, "선택 삭제"), /* @__PURE__ */ n.createElement("dt", null, "Esc"), /* @__PURE__ */ n.createElement("dd", null, "선택/페인트 해제"))), /* @__PURE__ */ n.createElement("section", null, /* @__PURE__ */ n.createElement("h4", null, "Preview"), /* @__PURE__ */ n.createElement("dl", null, /* @__PURE__ */ n.createElement("dt", null, "↑ / ↓"), /* @__PURE__ */ n.createElement("dd", null, "레이어 (Shift 10단계)"), /* @__PURE__ */ n.createElement("dt", null, "L"), /* @__PURE__ */ n.createElement("dd", null, "단일 레이어"), /* @__PURE__ */ n.createElement("dt", null, "T"), /* @__PURE__ */ n.createElement("dd", null, "트래블"), /* @__PURE__ */ n.createElement("dt", null, "Esc"), /* @__PURE__ */ n.createElement("dd", null, "Prepare 로"))), /* @__PURE__ */ n.createElement("section", null, /* @__PURE__ */ n.createElement("h4", null, "공통"), /* @__PURE__ */ n.createElement("dl", null, /* @__PURE__ */ n.createElement("dt", null, "Ctrl+R"), /* @__PURE__ */ n.createElement("dd", null, "슬라이스"), /* @__PURE__ */ n.createElement("dt", null, "Ctrl+K / ⌘D"), /* @__PURE__ */ n.createElement("dd", null, "복제"), /* @__PURE__ */ n.createElement("dt", null, "Ctrl+C/V/X"), /* @__PURE__ */ n.createElement("dd", null, "복사/붙여넣기/잘라내기"), /* @__PURE__ */ n.createElement("dt", null, "Z / B"), /* @__PURE__ */ n.createElement("dd", null, "전체 / 베드로 줌"))))))
|
|
1048
|
-
), W && G === "prepare" && /* @__PURE__ */ n.createElement("div", { className: "vp-top-toolbar", role: "toolbar", "aria-label": "오브젝트 도구" }, Vr.map((e, t) => {
|
|
1049
|
-
var r;
|
|
1050
|
-
return e.sep ? /* @__PURE__ */ n.createElement("span", { key: "sep" + t, className: "vtt-sep" }) : /* @__PURE__ */ n.createElement(
|
|
1163
|
+
return { duplicateSelected: P, copySelected: M, pasteClipboard: B, deleteSelected: ee, deleteAllObjects: L, splitSelected: te, setGizmo: I };
|
|
1164
|
+
}
|
|
1165
|
+
function zr({ showTabs: n, canvasMode: a, onCanvasMode: c, previewEnabled: l, onOpen: r }) {
|
|
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: r, title: "Open a model file — every existing object is cleared", "data-testid": "open-file" }, /* @__PURE__ */ e.createElement("img", { src: mr, alt: "" }), /* @__PURE__ */ e.createElement("span", null, "Open"))), n && /* @__PURE__ */ e.createElement("div", { className: "tb-tabs", role: "tablist", "aria-label": "Canvas mode" }, /* @__PURE__ */ e.createElement("button", { role: "tab", className: a === "prepare" ? "on" : "", onClick: () => c("prepare"), "data-testid": "mode-prepare", title: "Arrange, transform and paint supports" }, "Prepare"), /* @__PURE__ */ e.createElement("button", { role: "tab", className: a === "preview" ? "on" : "", onClick: () => c("preview"), disabled: !l, "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
|
+
}
|
|
1168
|
+
function Pr({ gizmoMode: n, paintMode: a, onGizmo: c, onTogglePaint: l }) {
|
|
1169
|
+
const r = (m) => n === m && a === "off" ? "on" : "";
|
|
1170
|
+
return /* @__PURE__ */ e.createElement("nav", { className: "left-rail", role: "toolbar", "aria-label": "Gizmo tools" }, /* @__PURE__ */ e.createElement("button", { className: r("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: dr, alt: "Move" })), /* @__PURE__ */ e.createElement("button", { className: r("rotate"), onClick: () => c("rotate"), title: "Rotate the object — PageUp/PageDown rotates in 45° steps (R)", "data-testid": "gizmo-rotate" }, /* @__PURE__ */ e.createElement("img", { src: gr, alt: "Rotate" })), /* @__PURE__ */ e.createElement("button", { className: r("scale"), onClick: () => c("scale"), title: "Scale the object (S)", "data-testid": "gizmo-scale" }, /* @__PURE__ */ e.createElement("img", { src: br, alt: "Scale" })), /* @__PURE__ */ e.createElement("div", { className: "rail-sep" }), /* @__PURE__ */ e.createElement("button", { className: a !== "off" ? "on" : "", onClick: l, title: "Brush facets to enforce or block support — the wheel changes the brush size", "data-testid": "gizmo-paint" }, /* @__PURE__ */ e.createElement("img", { src: hr, alt: "Support painting" })));
|
|
1171
|
+
}
|
|
1172
|
+
function Lr({ tools: n }) {
|
|
1173
|
+
return /* @__PURE__ */ e.createElement("div", { className: "vp-top-toolbar", role: "toolbar", "aria-label": "Object tools" }, n.map((a, c) => {
|
|
1174
|
+
var l;
|
|
1175
|
+
return a.sep ? /* @__PURE__ */ e.createElement("span", { key: "sep" + c, className: "vtt-sep" }) : /* @__PURE__ */ e.createElement(
|
|
1051
1176
|
"button",
|
|
1052
1177
|
{
|
|
1053
|
-
key:
|
|
1054
|
-
onClick:
|
|
1055
|
-
disabled: ((
|
|
1056
|
-
title:
|
|
1057
|
-
"data-testid": `tool-${
|
|
1178
|
+
key: a.id,
|
|
1179
|
+
onClick: a.run,
|
|
1180
|
+
disabled: ((l = a.disabled) == null ? void 0 : l.call(a)) ?? !a.run,
|
|
1181
|
+
title: a.tip,
|
|
1182
|
+
"data-testid": `tool-${a.id}`
|
|
1058
1183
|
},
|
|
1059
|
-
/* @__PURE__ */
|
|
1184
|
+
/* @__PURE__ */ e.createElement("img", { src: a.icon, alt: a.label })
|
|
1060
1185
|
);
|
|
1061
|
-
}))
|
|
1186
|
+
}));
|
|
1187
|
+
}
|
|
1188
|
+
function Or({ menu: n, onClose: a, canPaste: c, actions: l }) {
|
|
1189
|
+
const r = (m) => () => {
|
|
1190
|
+
a(), m == null || m();
|
|
1191
|
+
};
|
|
1192
|
+
return /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement("div", { className: "ctx-scrim", onPointerDown: a, onContextMenu: (m) => {
|
|
1193
|
+
m.preventDefault(), a();
|
|
1194
|
+
} }), /* @__PURE__ */ e.createElement("div", { className: "ctx-menu", style: { left: n.x, top: n.y }, "data-testid": "ctx-menu" }, n.onObject ? /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement("button", { onClick: r(l.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: r(l.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: r(l.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: r(l.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: r(l.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: r(l.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: r(l.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: r(l.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: r(l.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")))));
|
|
1195
|
+
}
|
|
1196
|
+
function Tr({ onClose: n }) {
|
|
1197
|
+
return /* @__PURE__ */ e.createElement("div", { className: "help-overlay", "data-testid": "help-overlay", onClick: n }, /* @__PURE__ */ e.createElement("div", { className: "help-card", onClick: (a) => a.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"))))));
|
|
1198
|
+
}
|
|
1199
|
+
function Br({ paintMode: n, onPaintMode: a, onClear: c, brushRadius: l, onBrushRadius: r, paintCounts: m }) {
|
|
1200
|
+
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: n === "enforcer" ? "on enf" : "enf", onClick: () => a("enforcer"), title: "Force support under the painted facets", "data-testid": "paint-enforcer" }, "enforcer"), /* @__PURE__ */ e.createElement("button", { className: n === "blocker" ? "on blk" : "blk", onClick: () => a("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: () => a("off"), "data-testid": "paint-off", title: "Leave painting mode (Esc)" }, "Close")), /* @__PURE__ */ e.createElement("label", { className: "bp-radius" }, "Brush radius ", l, "mm", /* @__PURE__ */ e.createElement(
|
|
1062
1201
|
"input",
|
|
1063
1202
|
{
|
|
1064
1203
|
type: "range",
|
|
1065
1204
|
min: "1",
|
|
1066
1205
|
max: "15",
|
|
1067
1206
|
step: "0.5",
|
|
1068
|
-
value:
|
|
1069
|
-
onChange: (
|
|
1070
|
-
const t = parseFloat(e.target.value);
|
|
1071
|
-
ln(t), Ke.current = t;
|
|
1072
|
-
},
|
|
1207
|
+
value: l,
|
|
1208
|
+
onChange: (d) => r(parseFloat(d.target.value)),
|
|
1073
1209
|
"data-testid": "brush-radius"
|
|
1074
1210
|
}
|
|
1075
|
-
)), /* @__PURE__ */
|
|
1211
|
+
)), /* @__PURE__ */ e.createElement("div", { className: "muted bp-counts", "data-testid": "paint-counts" }, "enforcer ", m.enf, " · blocker ", m.blk, " · drag over the model to paint"));
|
|
1212
|
+
}
|
|
1213
|
+
function Dr({ plateCount: n, selectedPlate: a, maxPlates: c, onSelect: l, onAdd: r, onDelete: m }) {
|
|
1214
|
+
return /* @__PURE__ */ e.createElement("div", { className: "plate-bar", "data-testid": "plate-bar", role: "tablist", "aria-label": "Plates" }, Array.from({ length: n }, (d, w) => /* @__PURE__ */ e.createElement("button", { key: w, role: "tab", className: "plate-tab" + (w === a ? " on" : ""), onClick: () => l(w), title: `Select plate ${w + 1} — in Preview this switches to that plate's result`, "data-testid": `plate-${w}` }, w + 1)), /* @__PURE__ */ e.createElement("button", { className: "plate-add", onClick: r, disabled: n >= c, title: "Add an empty plate (max 9) — each plate slices and exports separately", "data-testid": "plate-add" }, "+"), n > 1 && /* @__PURE__ */ e.createElement("button", { className: "plate-del", onClick: m, title: "Delete the last plate and its slice result", "data-testid": "plate-del" }, "−"));
|
|
1215
|
+
}
|
|
1216
|
+
const Zt = (n) => `rgb(${Math.round(n[0] * 255)},${Math.round(n[1] * 255)},${Math.round(n[2] * 255)})`;
|
|
1217
|
+
function Zr({
|
|
1218
|
+
viewType: n,
|
|
1219
|
+
onViewType: a,
|
|
1220
|
+
layerCount: c,
|
|
1221
|
+
layerLo: l,
|
|
1222
|
+
layerHi: r,
|
|
1223
|
+
segCount: m,
|
|
1224
|
+
singleLayer: d,
|
|
1225
|
+
onLayerLo: w,
|
|
1226
|
+
onLayerHi: b,
|
|
1227
|
+
onToggleSingle: T,
|
|
1228
|
+
showTravel: P,
|
|
1229
|
+
onToggleTravel: M,
|
|
1230
|
+
colorRange: B,
|
|
1231
|
+
roleLegend: ee
|
|
1232
|
+
}) {
|
|
1233
|
+
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: n, onChange: a, "data-testid": "view-type-select", title: "What the toolpath colors represent — feature type, speed, layer height, width, fan, temperature" }, Xn.map((L) => /* @__PURE__ */ e.createElement("option", { key: L.key, value: L.key }, L.label)))), /* @__PURE__ */ e.createElement("label", null, "Layer ", /* @__PURE__ */ e.createElement("b", { "data-testid": "layer-range" }, d ? r + 1 : `${l + 1}..${r + 1}`), " / ", c, /* @__PURE__ */ e.createElement("span", { className: "muted" }, " (", m.toLocaleString(), " segments)")), /* @__PURE__ */ e.createElement("div", { className: "dual-slider" }, /* @__PURE__ */ e.createElement("input", { type: "range", min: "0", max: Math.max(0, c - 1), value: l, onChange: w, "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: r, onChange: b, "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: d ? "on" : "", onClick: T, "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: P, onChange: M, "data-testid": "travel-toggle", title: "Show non-extruding moves as gray lines (T)" }), " Travel")), B && B.cont ? /* @__PURE__ */ e.createElement("div", { className: "grad-legend", "data-testid": "view-legend" }, /* @__PURE__ */ e.createElement("div", { className: "grad-title" }, B.label, " ", /* @__PURE__ */ e.createElement("span", { className: "muted" }, B.unit)), /* @__PURE__ */ e.createElement("div", { className: "grad-bar", "data-testid": "gradient-bar", style: { background: `linear-gradient(to right, ${Kn.map(Zt).join(",")})` } }), /* @__PURE__ */ e.createElement("div", { className: "grad-minmax" }, /* @__PURE__ */ e.createElement("span", { "data-testid": "grad-min" }, B.min.toFixed(B.unit === "mm" ? 2 : 0)), /* @__PURE__ */ e.createElement("span", { "data-testid": "grad-max" }, B.max.toFixed(B.unit === "mm" ? 2 : 0)))) : /* @__PURE__ */ e.createElement("div", { className: "role-legend", "data-testid": "view-legend" }, ee.map((L) => /* @__PURE__ */ e.createElement("span", { key: L.type, className: "role-item" }, /* @__PURE__ */ e.createElement("i", { style: { background: Zt(L.color) } }), L.label, " ", /* @__PURE__ */ e.createElement("b", null, L.pct.toFixed(0), "%")))));
|
|
1234
|
+
}
|
|
1235
|
+
const Ir = (n) => {
|
|
1236
|
+
const a = Math.round(n);
|
|
1237
|
+
return `${Math.floor(a / 3600)}h ${String(Math.floor(a % 3600 / 60)).padStart(2, "0")}m ${String(a % 60).padStart(2, "0")}s`;
|
|
1238
|
+
}, Vr = { full: "GCodeProcessor", transcribed: "transcribed planner", fallback: "fallback" };
|
|
1239
|
+
function Fr({ stats: n, overBed: a }) {
|
|
1240
|
+
return n ? /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement("div", null, /* @__PURE__ */ e.createElement("b", null, n.layers), " layers · ", /* @__PURE__ */ e.createElement("b", null, n.segments), " segments"), /* @__PURE__ */ e.createElement("div", null, "Filament ", /* @__PURE__ */ e.createElement("b", null, n.filament.toFixed(1)), " mm"), typeof n.timeSec == "number" && n.timeSec > 0 && /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement("div", { "data-testid": "print-time" }, "⏱ Estimated print ", /* @__PURE__ */ e.createElement("b", null, Ir(n.timeSec))), n.limits && // What the estimator actually ran with, echoed back by the kernel — not re-derived from the settings,
|
|
1241
|
+
// so an unwired limit shows up as a mismatch here instead of being silently reported as applied.
|
|
1242
|
+
/* @__PURE__ */ e.createElement(
|
|
1243
|
+
"div",
|
|
1244
|
+
{
|
|
1245
|
+
className: "sc-sub",
|
|
1246
|
+
"data-testid": "print-time-basis",
|
|
1247
|
+
title: Object.entries(n.limits).map(([c, l]) => `${c}: ${l}`).join(`
|
|
1248
|
+
`)
|
|
1249
|
+
},
|
|
1250
|
+
Vr[n.engine] ?? n.engine,
|
|
1251
|
+
" · ",
|
|
1252
|
+
n.limits.max_speed_xy,
|
|
1253
|
+
" mm/s · ",
|
|
1254
|
+
n.limits.accel_print,
|
|
1255
|
+
" mm/s² · jerk ",
|
|
1256
|
+
n.limits.jerk_xy
|
|
1257
|
+
)), a && /* @__PURE__ */ e.createElement("div", { className: "slice-warn", "data-testid": "over-bed" }, "⚠ Model extends beyond the bed")) : null;
|
|
1258
|
+
}
|
|
1259
|
+
function Gr({ bedWidth: n, bedDepth: a, nozzleDia: c, onBedSize: l, settings: r, setSettings: m, motionPanel: d }) {
|
|
1260
|
+
const w = Tt(() => Object.entries(On).sort(([h], [E]) => h.localeCompare(E)), []), b = (r == null ? void 0 : r.printer_settings_id) ?? "", T = Tt(() => {
|
|
1261
|
+
const h = /* @__PURE__ */ new Map();
|
|
1262
|
+
for (const [E, k] of w)
|
|
1263
|
+
for (const [j, [f, , g]] of Object.entries(k)) {
|
|
1264
|
+
const y = `${E}\0${g}`;
|
|
1265
|
+
h.has(y) || h.set(y, { vendor: E, model: g, variants: [] }), h.get(y).variants.push({ name: j, nozzle: f });
|
|
1266
|
+
}
|
|
1267
|
+
for (const E of h.values()) E.variants.sort((k, j) => parseFloat(k.nozzle) - parseFloat(j.nozzle));
|
|
1268
|
+
return h;
|
|
1269
|
+
}, [w]), P = [...T.entries()].find(([, h]) => h.variants.some((E) => E.name === b)), M = (P == null ? void 0 : P[1].variants) ?? [], [B, ee] = $(null), L = (h) => m == null ? void 0 : m((E) => {
|
|
1270
|
+
const k = { ...E };
|
|
1271
|
+
for (const f of lt) delete k[f];
|
|
1272
|
+
for (const f of (B == null ? void 0 : B.keys) ?? []) delete k[f];
|
|
1273
|
+
delete k.printer_settings_id, delete k.print_settings_id;
|
|
1274
|
+
const j = h ? Zn(h) : null;
|
|
1275
|
+
return j ? { ...k, ...j, printer_settings_id: h } : k;
|
|
1276
|
+
});
|
|
1277
|
+
Ve(() => {
|
|
1278
|
+
if (!b) return;
|
|
1279
|
+
let h = !0;
|
|
1280
|
+
return Tn().then((E) => {
|
|
1281
|
+
if (!h) return;
|
|
1282
|
+
ee(E);
|
|
1283
|
+
const k = Bn(b);
|
|
1284
|
+
m == null || m((j) => {
|
|
1285
|
+
if (j.printer_settings_id !== b || j.print_settings_id) return j;
|
|
1286
|
+
const f = k && E.listFor(b).includes(k) ? E.settingsFor(k) : null;
|
|
1287
|
+
if (!f) return j;
|
|
1288
|
+
for (const g of lt) delete f[g];
|
|
1289
|
+
return { ...j, ...f, print_settings_id: k };
|
|
1290
|
+
});
|
|
1291
|
+
}), () => {
|
|
1292
|
+
h = !1;
|
|
1293
|
+
};
|
|
1294
|
+
}, [b]);
|
|
1295
|
+
const te = B && b ? B.listFor(b) : [], I = (h) => m == null ? void 0 : m((E) => {
|
|
1296
|
+
const k = { ...E };
|
|
1297
|
+
for (const f of B.keys)
|
|
1298
|
+
lt.includes(f) || delete k[f];
|
|
1299
|
+
delete k.print_settings_id;
|
|
1300
|
+
const j = h ? B.settingsFor(h) : null;
|
|
1301
|
+
if (!j) return k;
|
|
1302
|
+
for (const f of lt) delete j[f];
|
|
1303
|
+
return { ...k, ...j, print_settings_id: h };
|
|
1304
|
+
}), A = (h) => {
|
|
1305
|
+
const E = T.get(h);
|
|
1306
|
+
if (!E) return L("");
|
|
1307
|
+
const k = E.variants.find((j) => {
|
|
1308
|
+
var f;
|
|
1309
|
+
return j.nozzle === ((f = M.find((g) => g.name === b)) == null ? void 0 : f.nozzle);
|
|
1310
|
+
});
|
|
1311
|
+
L((k ?? E.variants[Math.min(1, E.variants.length - 1)]).name);
|
|
1312
|
+
}, u = Dn.filter((h) => r && h in r), _ = Math.round(n), G = Math.round(a), K = (h) => {
|
|
1313
|
+
h.key === "Enter" && h.target.blur();
|
|
1314
|
+
};
|
|
1315
|
+
return /* @__PURE__ */ e.createElement("section", { className: "side-card" }, /* @__PURE__ */ e.createElement("div", { className: "sc-head" }, "🖨 Printer"), m && /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement("div", { className: "sc-info" }, /* @__PURE__ */ e.createElement("span", null, "Model"), /* @__PURE__ */ e.createElement(
|
|
1316
|
+
"select",
|
|
1317
|
+
{
|
|
1318
|
+
className: "sc-model",
|
|
1319
|
+
value: (P == null ? void 0 : P[0]) ?? "",
|
|
1320
|
+
onChange: (h) => A(h.target.value),
|
|
1321
|
+
"data-testid": "printer-model",
|
|
1322
|
+
title: "Loads this printer's profile (motion limits, bed, nozzle) from the upstream vendor data"
|
|
1323
|
+
},
|
|
1324
|
+
/* @__PURE__ */ e.createElement("option", { value: "" }, "Custom (defaults)"),
|
|
1325
|
+
w.map(([h]) => /* @__PURE__ */ e.createElement("optgroup", { key: h, label: h }, [...T.entries()].filter(([, E]) => E.vendor === h).map(([E, k]) => /* @__PURE__ */ e.createElement("option", { key: E, value: E }, k.model))))
|
|
1326
|
+
)), M.length > 1 && /* @__PURE__ */ e.createElement("div", { className: "sc-info" }, /* @__PURE__ */ e.createElement("span", null, "Nozzle"), /* @__PURE__ */ e.createElement("select", { className: "sc-model", value: b, onChange: (h) => L(h.target.value), "data-testid": "printer-nozzle" }, M.map((h) => /* @__PURE__ */ e.createElement("option", { key: h.name, value: h.name }, h.nozzle, " mm")))), te.length > 0 && /* @__PURE__ */ e.createElement("div", { className: "sc-info" }, /* @__PURE__ */ e.createElement("span", null, "Quality"), /* @__PURE__ */ e.createElement(
|
|
1327
|
+
"select",
|
|
1328
|
+
{
|
|
1329
|
+
className: "sc-model",
|
|
1330
|
+
value: (r == null ? void 0 : r.print_settings_id) ?? "",
|
|
1331
|
+
onChange: (h) => I(h.target.value),
|
|
1332
|
+
"data-testid": "process-preset",
|
|
1333
|
+
title: "Print preset from the vendor profile — the speeds and accelerations the printer is actually driven at"
|
|
1334
|
+
},
|
|
1335
|
+
/* @__PURE__ */ e.createElement("option", { value: "" }, "Custom (defaults)"),
|
|
1336
|
+
te.map((h) => /* @__PURE__ */ e.createElement("option", { key: h, value: h }, h.replace(/\s*@.*$/, "")))
|
|
1337
|
+
))), /* @__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(
|
|
1076
1338
|
"input",
|
|
1077
1339
|
{
|
|
1078
1340
|
type: "number",
|
|
1079
1341
|
min: "1",
|
|
1080
|
-
key: `w${
|
|
1081
|
-
defaultValue:
|
|
1082
|
-
onBlur: (
|
|
1083
|
-
onKeyDown:
|
|
1084
|
-
e.key === "Enter" && e.target.blur();
|
|
1085
|
-
},
|
|
1342
|
+
key: `w${_}`,
|
|
1343
|
+
defaultValue: _,
|
|
1344
|
+
onBlur: (h) => l(+h.target.value, a),
|
|
1345
|
+
onKeyDown: K,
|
|
1086
1346
|
"data-testid": "bed-w-card"
|
|
1087
1347
|
}
|
|
1088
|
-
), "×", /* @__PURE__ */
|
|
1348
|
+
), "×", /* @__PURE__ */ e.createElement(
|
|
1089
1349
|
"input",
|
|
1090
1350
|
{
|
|
1091
1351
|
type: "number",
|
|
1092
1352
|
min: "1",
|
|
1093
|
-
key: `d${
|
|
1094
|
-
defaultValue:
|
|
1095
|
-
onBlur: (
|
|
1096
|
-
onKeyDown:
|
|
1097
|
-
e.key === "Enter" && e.target.blur();
|
|
1098
|
-
},
|
|
1353
|
+
key: `d${G}`,
|
|
1354
|
+
defaultValue: G,
|
|
1355
|
+
onBlur: (h) => l(n, +h.target.value),
|
|
1356
|
+
onKeyDown: K,
|
|
1099
1357
|
"data-testid": "bed-d-card"
|
|
1100
1358
|
}
|
|
1101
|
-
), "mm")), /* @__PURE__ */
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1359
|
+
), "mm")), /* @__PURE__ */ e.createElement("div", { className: "sc-info" }, /* @__PURE__ */ e.createElement("span", null, "Nozzle Ø"), /* @__PURE__ */ e.createElement("b", null, c, " mm")), d ? /* @__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" }, u.length ? `Custom (${u.length})` : "Default")), /* @__PURE__ */ e.createElement("div", { className: "sc-fold-body" }, d)) : /* @__PURE__ */ e.createElement("div", { className: "sc-info" }, /* @__PURE__ */ e.createElement("span", null, "Motion"), /* @__PURE__ */ e.createElement(
|
|
1360
|
+
"b",
|
|
1361
|
+
{
|
|
1362
|
+
"data-testid": "motion-source",
|
|
1363
|
+
title: u.length ? `Edited: ${u.join(", ")}` : "Machine limits are at their defaults"
|
|
1364
|
+
},
|
|
1365
|
+
u.length ? `Custom (${u.length})` : "Default"
|
|
1366
|
+
)));
|
|
1367
|
+
}
|
|
1368
|
+
function Ur({ colors: n, onColor: a, onAdd: c, onRemove: l }) {
|
|
1369
|
+
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" }, n.length), /* @__PURE__ */ e.createElement("span", { className: "sc-head-btns" }, /* @__PURE__ */ e.createElement("button", { onClick: c, disabled: n.length >= 4, title: "Add a filament (extruder) — up to 4, assignable per object", "data-testid": "filament-add" }, "+"), /* @__PURE__ */ e.createElement("button", { onClick: l, disabled: n.length <= 1, title: "Remove the last filament — objects using it are reassigned to a remaining number", "data-testid": "filament-del" }, "−"))), n.map((r, m) => /* @__PURE__ */ e.createElement("div", { className: "filament-row", key: m }, /* @__PURE__ */ e.createElement("input", { type: "color", value: r, onChange: (d) => a(m, d.target.value), title: `T${m + 1} filament color`, "data-testid": `filament-color-${m}` }), /* @__PURE__ */ e.createElement("span", { className: "fil-t" }, "T", m + 1), /* @__PURE__ */ e.createElement("span", { className: "fil-swatch", style: { background: r } }), /* @__PURE__ */ e.createElement("span", { className: "fil-hex muted" }, r))));
|
|
1370
|
+
}
|
|
1371
|
+
function $r({
|
|
1372
|
+
objects: n,
|
|
1373
|
+
extruderColors: a,
|
|
1374
|
+
onToggleVisible: c,
|
|
1375
|
+
onExtruder: l,
|
|
1376
|
+
onSplit: r,
|
|
1377
|
+
onRemove: m,
|
|
1378
|
+
supportOn: d,
|
|
1379
|
+
onToggleSupport: w,
|
|
1380
|
+
wipeTowerReal: b,
|
|
1381
|
+
onToggleWipeTower: T,
|
|
1382
|
+
overhangOn: P,
|
|
1383
|
+
onToggleOverhang: M,
|
|
1384
|
+
overhangAngle: B,
|
|
1385
|
+
paintMode: ee,
|
|
1386
|
+
onTogglePaint: L,
|
|
1387
|
+
supportStyle: te,
|
|
1388
|
+
supportStyles: I,
|
|
1389
|
+
onSupportStyle: A
|
|
1390
|
+
}) {
|
|
1391
|
+
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" }, n.length)), /* @__PURE__ */ e.createElement("ul", { className: "obj-list2", "data-testid": "obj-list" }, n.map((u) => /* @__PURE__ */ e.createElement("li", { key: u.id, className: u.visible === !1 ? "obj-hidden" : "" }, /* @__PURE__ */ e.createElement("button", { className: "obj-eye", onClick: () => c(u.id), title: "Include/exclude this object from printing — excluding it keeps it in the scene", "data-testid": `eye-${u.id}` }, /* @__PURE__ */ e.createElement("img", { src: u.visible === !1 ? sr : lr, alt: u.visible === !1 ? "Hidden" : "Visible" })), /* @__PURE__ */ e.createElement("span", { className: "obj-name", title: u.name }, u.name), /* @__PURE__ */ e.createElement("select", { className: "obj-ext", value: u.extruder ?? 1, onChange: (_) => l(u.id, +_.target.value), title: "Which filament (extruder) prints this object", "data-testid": `ext-${u.id}` }, a.map((_, G) => /* @__PURE__ */ e.createElement("option", { key: G, value: G + 1 }, "T", G + 1))), /* @__PURE__ */ e.createElement("button", { className: "obj-split", onClick: () => r(u.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-${u.id}` }, /* @__PURE__ */ e.createElement("img", { src: Gt, alt: "Split" })), /* @__PURE__ */ e.createElement("button", { className: "obj-del", onClick: () => m(u.id), title: "Remove this object from the scene" }, /* @__PURE__ */ e.createElement("img", { src: Ft, alt: "Delete" }))))), /* @__PURE__ */ e.createElement("label", { className: "slice-support" }, /* @__PURE__ */ e.createElement("input", { type: "checkbox", checked: d, onChange: w, title: "Generate support structures under overhangs (same as enable_support in the settings panel)", "data-testid": "support-toggle" }), " Generate support"), d && /* @__PURE__ */ e.createElement("div", { className: "sc-info sup-style" }, /* @__PURE__ */ e.createElement("span", null, "Style"), /* @__PURE__ */ e.createElement(
|
|
1392
|
+
"select",
|
|
1393
|
+
{
|
|
1394
|
+
className: "sc-model",
|
|
1395
|
+
value: te,
|
|
1396
|
+
onChange: (u) => A(u.target.value),
|
|
1397
|
+
"data-testid": "support-style",
|
|
1398
|
+
title: "Support style (support_style). The kernel builds the tree/organic family as real tree support; the rest as grid."
|
|
1399
|
+
},
|
|
1400
|
+
I.map((u) => /* @__PURE__ */ e.createElement("option", { key: u.value, value: u.value }, u.label))
|
|
1401
|
+
)), d && /* @__PURE__ */ e.createElement("div", { className: "support-tools" }, /* @__PURE__ */ e.createElement("label", { className: "slice-support" }, /* @__PURE__ */ e.createElement(
|
|
1402
|
+
"input",
|
|
1403
|
+
{
|
|
1404
|
+
type: "checkbox",
|
|
1405
|
+
checked: !!P,
|
|
1406
|
+
onChange: M,
|
|
1407
|
+
title: `Shade the facets that will need support (slope below ${B}°, the support threshold angle)`,
|
|
1408
|
+
"data-testid": "overhang-toggle"
|
|
1409
|
+
}
|
|
1410
|
+
), " Show overhangs ", /* @__PURE__ */ e.createElement("span", { className: "muted" }, "<", B, "°")), /* @__PURE__ */ e.createElement(
|
|
1411
|
+
"button",
|
|
1412
|
+
{
|
|
1413
|
+
className: ee !== "off" ? "sup-paint on" : "sup-paint",
|
|
1414
|
+
onClick: L,
|
|
1415
|
+
disabled: !n.length,
|
|
1416
|
+
"data-testid": "support-paint-btn",
|
|
1417
|
+
title: "Brush facets to force or block support — the same tool as the paint icon on the left rail"
|
|
1418
|
+
},
|
|
1419
|
+
ee !== "off" ? "Painting…" : "Paint support"
|
|
1420
|
+
)), /* @__PURE__ */ e.createElement("label", { className: "slice-support" }, /* @__PURE__ */ e.createElement("input", { type: "checkbox", checked: b, onChange: T, title: "Use the upstream WipeTower to compute purge volumes on multi-material tool changes (off = a simple square ring)", "data-testid": "wipe-tower-real-toggle" }), " Real wipe tower ", /* @__PURE__ */ e.createElement("span", { className: "muted" }, "(MM)")));
|
|
1421
|
+
}
|
|
1422
|
+
function Hr({
|
|
1423
|
+
autoSlice: n,
|
|
1424
|
+
onAutoSlice: a,
|
|
1425
|
+
slicing: c,
|
|
1426
|
+
progress: l,
|
|
1427
|
+
plateCount: r,
|
|
1428
|
+
selectedPlate: m,
|
|
1429
|
+
sliceMenuOpen: d,
|
|
1430
|
+
onSliceMenu: w,
|
|
1431
|
+
slicedPlateCount: b,
|
|
1432
|
+
canSlice: T,
|
|
1433
|
+
onSlice: P,
|
|
1434
|
+
onCancel: M,
|
|
1435
|
+
onExportAll: B,
|
|
1436
|
+
gcodeUrl: ee
|
|
1437
|
+
}) {
|
|
1438
|
+
const L = c ? "Click to cancel the slice" : r > 1 ? "Choose what to slice (Ctrl+R = current plate)" : "Slice the current plate (Ctrl+R)";
|
|
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: n, onChange: (te) => a(te.target.checked) }), " Auto slice"), /* @__PURE__ */ e.createElement("div", { className: "slice-dd" }, /* @__PURE__ */ e.createElement(
|
|
1440
|
+
"button",
|
|
1441
|
+
{
|
|
1442
|
+
className: "slice-btn",
|
|
1443
|
+
title: L,
|
|
1444
|
+
onClick: () => c ? M() : r > 1 ? w() : P("current"),
|
|
1445
|
+
disabled: !T,
|
|
1446
|
+
"data-testid": "slice-btn"
|
|
1447
|
+
},
|
|
1448
|
+
c ? `Slicing… ${Math.round(l * 100)}%` : r > 1 ? "Slice ▾" : "Slice"
|
|
1449
|
+
), d && r > 1 && /* @__PURE__ */ e.createElement("div", { className: "slice-menu", "data-testid": "slice-menu" }, /* @__PURE__ */ e.createElement("button", { onClick: () => P("current"), "data-testid": "slice-current", title: "Slice only the selected plate (Ctrl+R)" }, "Current plate (P", m + 1, ")"), /* @__PURE__ */ e.createElement("button", { onClick: () => P("all"), "data-testid": "slice-all", title: "Slice every plate in turn — switch tabs to inspect the results" }, "All plates (", r, ")"), b > 0 && /* @__PURE__ */ e.createElement("button", { onClick: B, "data-testid": "export-all", title: "Save the G-code of every sliced plate as its own file" }, "Export all G-code (", b, ")"))), ee ? /* @__PURE__ */ e.createElement("a", { className: "export-btn", href: ee, download: `plate_${m + 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
|
+
}
|
|
1451
|
+
function no({ settings: n = {}, setSettings: a = () => {
|
|
1452
|
+
}, processPanel: c = null, motionPanel: l = null }) {
|
|
1453
|
+
var Pt, Lt, Ot;
|
|
1454
|
+
const r = H(null), m = H(null), d = H([]), w = H(null), b = H(null), T = H(null), P = H({}), M = H(null), B = H(null), ee = H(!1), L = H("feature"), te = H(0), I = H(0), A = H("prepare"), u = H(0.42), _ = H("off"), G = H(5), K = H(null), h = H(null), E = H({}), k = H({}), j = H(0), f = H(1), g = H(0), [y, v] = $(!0), [D, W] = $("translate"), [oe, ge] = $("Initializing…"), [de, Y] = $([]), [C, pe] = $(""), [je, Ce] = $(!1), [ye, Re] = $(!1), be = H(0), [Se, i] = $(0), [S, V] = $(""), [p, O] = $(null), [ue, ve] = $(!1), [Ee, Z] = $(0), [q, z] = $(0), [ie, we] = $(1), [se, ae] = $(0), [J, ce] = $(!1), [ke, ze] = $(!1), [Fe, qe] = $(0), [Ie, We] = $(null), [et, tt] = $("feature"), [nt, Xe] = $(null), [rt, t] = $(0), [s, R] = $(0), [F, re] = $(!1), [U, me] = $([]), [ne, Me] = $("prepare"), [Ne, Pe] = $(!1), Ae = H(null), [De, Oe] = $(["#6aa0dc", "#e08a2b"]), Ze = H(["#6aa0dc", "#e08a2b"]), [fe, le] = $(""), [Le, _e] = $(!1), [Te, X] = $(!1), [xe, Ge] = $("off"), [Ue, yt] = $(5), [Ut, vt] = $({ enf: 0, blk: 0 }), [wt, st] = $(""), [kt, Et] = $(null), { mountRef: $t, three: ot } = jr({
|
|
1455
|
+
apiRef: r,
|
|
1456
|
+
objectsRef: d,
|
|
1457
|
+
keyRef: M,
|
|
1458
|
+
workerRef: m,
|
|
1459
|
+
selectedPlateRef: j,
|
|
1460
|
+
placeXRef: g,
|
|
1461
|
+
plateCountRef: f,
|
|
1462
|
+
canvasModeRef: A,
|
|
1463
|
+
paintModeRef: _,
|
|
1464
|
+
brushRadiusRef: G,
|
|
1465
|
+
paintXformRef: K,
|
|
1466
|
+
extruderColorsRef: Ze,
|
|
1467
|
+
setOk: v,
|
|
1468
|
+
setStatus: ge,
|
|
1469
|
+
setGmode: W,
|
|
1470
|
+
setCtxMenu: We,
|
|
1471
|
+
setBrushRadius: yt
|
|
1472
|
+
}), $e = xt(n);
|
|
1473
|
+
Ve(() => {
|
|
1474
|
+
var o;
|
|
1475
|
+
(o = r.current) == null || o.setPlates(ie, $e.bed_width, $e.bed_depth, se);
|
|
1476
|
+
}, [$e.bed_width, $e.bed_depth, ie, se]), Ve(() => {
|
|
1477
|
+
var Q;
|
|
1478
|
+
A.current = ne;
|
|
1479
|
+
const o = ot.current;
|
|
1480
|
+
if (!o.toolpathGroup) return;
|
|
1481
|
+
const x = ne === "preview";
|
|
1482
|
+
o.toolpathGroup.visible = x, o.objectsGroup && (o.objectsGroup.visible = !x && d.current.length > 0), x && ((Q = r.current) == null || Q.detachTransform(), _.current !== "off" && Ke("off"));
|
|
1483
|
+
}, [ne]);
|
|
1484
|
+
const {
|
|
1485
|
+
disposePlateToolpath: Ht,
|
|
1486
|
+
clearToolpaths: qt,
|
|
1487
|
+
buildPlateToolpath: Wt,
|
|
1488
|
+
ensurePlateToolpaths: Xt,
|
|
1489
|
+
applyViewColors: Mt,
|
|
1490
|
+
rebuildToolpaths: Kt,
|
|
1491
|
+
applyLayerRange: Yt
|
|
1492
|
+
} = Sr({
|
|
1493
|
+
three: ot,
|
|
1494
|
+
plateTpRef: P,
|
|
1495
|
+
toolpathRef: b,
|
|
1496
|
+
segDataRef: T,
|
|
1497
|
+
layersDataRef: w,
|
|
1498
|
+
plateResultsRef: E,
|
|
1499
|
+
plateOffsetsRef: k,
|
|
1500
|
+
lineWidthRef: u,
|
|
1501
|
+
showTravelRef: ee,
|
|
1502
|
+
viewTypeRef: L,
|
|
1503
|
+
layerLoRef: te,
|
|
1504
|
+
layerHiRef: I,
|
|
1505
|
+
selectedPlateRef: j,
|
|
1506
|
+
settings: n,
|
|
1507
|
+
setSegCount: z,
|
|
1508
|
+
setColorRange: Xe,
|
|
1509
|
+
setRoleLegend: me
|
|
1510
|
+
}), { getWorker: Jt, cancelSlice: jt, runSlice: Qt, pendingSliceRef: en, downgradeRef: tn } = Cr({
|
|
1511
|
+
settings: n,
|
|
1512
|
+
wipeTowerReal: Te,
|
|
1513
|
+
workerRef: m,
|
|
1514
|
+
apiRef: r,
|
|
1515
|
+
layersDataRef: w,
|
|
1516
|
+
layerLoRef: te,
|
|
1517
|
+
layerHiRef: I,
|
|
1518
|
+
rebuildToolpaths: Kt,
|
|
1519
|
+
rebuildPaintOverlay: (o, x) => nn(o, x),
|
|
1520
|
+
setProgress: i,
|
|
1521
|
+
setSlicing: Ce,
|
|
1522
|
+
setError: V,
|
|
1523
|
+
setStats: O,
|
|
1524
|
+
setOverBed: ve,
|
|
1525
|
+
setLayerCount: Z,
|
|
1526
|
+
setLayerLo: t,
|
|
1527
|
+
setLayerHi: R,
|
|
1528
|
+
setGcodeUrl: le,
|
|
1529
|
+
setCanvasMode: Me,
|
|
1530
|
+
setPaintCounts: vt
|
|
1531
|
+
}), { rebuildPaintOverlay: nn, setPaintMode: Ke, clearPaint: rn } = Ar({
|
|
1532
|
+
three: ot,
|
|
1533
|
+
objectsRef: d,
|
|
1534
|
+
apiRef: r,
|
|
1535
|
+
getWorker: Jt,
|
|
1536
|
+
selectedPlateRef: j,
|
|
1537
|
+
paintXformRef: K,
|
|
1538
|
+
paintOverlayRef: h,
|
|
1539
|
+
paintModeRef: _,
|
|
1540
|
+
setError: V,
|
|
1541
|
+
setPaintModeState: Ge,
|
|
1542
|
+
setPaintCounts: vt
|
|
1543
|
+
}), {
|
|
1544
|
+
refreshSlicedCount: on,
|
|
1545
|
+
exportAllGcode: an,
|
|
1546
|
+
onSlice: it,
|
|
1547
|
+
retryDowngrade: ln,
|
|
1548
|
+
addPlate: sn,
|
|
1549
|
+
deletePlate: cn,
|
|
1550
|
+
selectPlate: dn
|
|
1551
|
+
} = Rr({
|
|
1552
|
+
apiRef: r,
|
|
1553
|
+
selectedPlateRef: j,
|
|
1554
|
+
plateCountRef: f,
|
|
1555
|
+
placeXRef: g,
|
|
1556
|
+
plateResultsRef: E,
|
|
1557
|
+
plateOffsetsRef: k,
|
|
1558
|
+
plateTpRef: P,
|
|
1559
|
+
layersDataRef: w,
|
|
1560
|
+
toolpathRef: b,
|
|
1561
|
+
segDataRef: T,
|
|
1562
|
+
layerLoRef: te,
|
|
1563
|
+
layerHiRef: I,
|
|
1564
|
+
lineWidthRef: u,
|
|
1565
|
+
downgradeRef: tn,
|
|
1566
|
+
settings: n,
|
|
1567
|
+
canvasMode: ne,
|
|
1568
|
+
downgradeOffer: kt,
|
|
1569
|
+
runSlice: Qt,
|
|
1570
|
+
ensurePlateToolpaths: Xt,
|
|
1571
|
+
buildPlateToolpath: Wt,
|
|
1572
|
+
applyViewColors: Mt,
|
|
1573
|
+
disposePlateToolpath: Ht,
|
|
1574
|
+
setStats: O,
|
|
1575
|
+
setOverBed: ve,
|
|
1576
|
+
setLayerCount: Z,
|
|
1577
|
+
setSegCount: z,
|
|
1578
|
+
setColorRange: Xe,
|
|
1579
|
+
setRoleLegend: me,
|
|
1580
|
+
setGcodeUrl: le,
|
|
1581
|
+
setLayerLo: t,
|
|
1582
|
+
setLayerHi: R,
|
|
1583
|
+
setCanvasMode: Me,
|
|
1584
|
+
setSlicedPlateCount: qe,
|
|
1585
|
+
setSliceMenu: ce,
|
|
1586
|
+
setError: V,
|
|
1587
|
+
setSliceNotice: st,
|
|
1588
|
+
setDowngradeOffer: Et,
|
|
1589
|
+
setSlicing: Ce,
|
|
1590
|
+
setProgress: i,
|
|
1591
|
+
setPlateCount: we,
|
|
1592
|
+
setSelectedPlate: ae
|
|
1593
|
+
}), { onFiles: pn, removeObject: Ct, onDrop: un, onDragOver: mn, onDragLeave: fn } = Nr({
|
|
1594
|
+
apiRef: r,
|
|
1595
|
+
objectsRef: d,
|
|
1596
|
+
layersDataRef: w,
|
|
1597
|
+
segDataRef: T,
|
|
1598
|
+
plateResultsRef: E,
|
|
1599
|
+
plateOffsetsRef: k,
|
|
1600
|
+
clearToolpaths: qt,
|
|
1601
|
+
refreshSlicedCount: on,
|
|
1602
|
+
dragOver: Ne,
|
|
1603
|
+
setError: V,
|
|
1604
|
+
setTriWarn: pe,
|
|
1605
|
+
setProgress: i,
|
|
1606
|
+
setStats: O,
|
|
1607
|
+
setOverBed: ve,
|
|
1608
|
+
setLayerCount: Z,
|
|
1609
|
+
setSegCount: z,
|
|
1610
|
+
setColorRange: Xe,
|
|
1611
|
+
setSliceNotice: st,
|
|
1612
|
+
setDowngradeOffer: Et,
|
|
1613
|
+
setGcodeUrl: le,
|
|
1614
|
+
setCanvasMode: Me,
|
|
1615
|
+
setObjects: Y,
|
|
1616
|
+
setDragOver: Pe
|
|
1617
|
+
});
|
|
1618
|
+
Ve(() => {
|
|
1619
|
+
if (!ye || !de.length || !E.current[j.current]) return;
|
|
1620
|
+
clearTimeout(be.current);
|
|
1621
|
+
const o = () => {
|
|
1622
|
+
if (en.current) {
|
|
1623
|
+
jt(), be.current = setTimeout(o, 300);
|
|
1624
|
+
return;
|
|
1625
|
+
}
|
|
1626
|
+
it("current");
|
|
1627
|
+
};
|
|
1628
|
+
return be.current = setTimeout(o, 800), () => clearTimeout(be.current);
|
|
1629
|
+
}, [n, ye]);
|
|
1630
|
+
function hn(o, x) {
|
|
1631
|
+
if (!(o > 0) || !(x > 0)) return;
|
|
1632
|
+
const Q = Je(n, "printable_area"), he = Array.isArray(Q) && Q.length >= 3, Be = he ? Math.min(...Q.map((Qe) => Qe[0])) : 0, at = he ? Math.min(...Q.map((Qe) => Qe[1])) : 0;
|
|
1633
|
+
a((Qe) => ({ ...Qe, printable_area: [[Be, at], [Be + o, at], [Be + o, at + x], [Be, at + x]] }));
|
|
1634
|
+
}
|
|
1635
|
+
function gn(o, x) {
|
|
1636
|
+
var Q;
|
|
1637
|
+
(Q = r.current) == null || Q.setObjectExtruder(o, x), Y(d.current.map((he) => ({ id: he.id, name: he.name, extruder: he.extruder, visible: he.visible !== !1 })));
|
|
1638
|
+
}
|
|
1639
|
+
function He(o, x) {
|
|
1640
|
+
const Q = Math.max(0, Ee - 1);
|
|
1641
|
+
if (o = Math.max(0, Math.min(Q, o)), x = Math.max(0, Math.min(Q, x)), o > x) {
|
|
1642
|
+
const he = o;
|
|
1643
|
+
o = x, x = he;
|
|
1644
|
+
}
|
|
1645
|
+
te.current = o, I.current = x, t(o), R(x), Yt();
|
|
1646
|
+
}
|
|
1647
|
+
function bn(o) {
|
|
1648
|
+
const x = parseInt(o.target.value, 10);
|
|
1649
|
+
F ? He(x, x) : He(x, I.current);
|
|
1650
|
+
}
|
|
1651
|
+
function xn(o) {
|
|
1652
|
+
const x = parseInt(o.target.value, 10);
|
|
1653
|
+
He(F ? x : te.current, x);
|
|
1654
|
+
}
|
|
1655
|
+
function St() {
|
|
1656
|
+
const o = !F;
|
|
1657
|
+
re(o), o && He(I.current, I.current);
|
|
1658
|
+
}
|
|
1659
|
+
function yn(o) {
|
|
1660
|
+
const x = o.target.value;
|
|
1661
|
+
tt(x), L.current = x, Mt();
|
|
1662
|
+
}
|
|
1663
|
+
function Rt(o) {
|
|
1664
|
+
const x = o.target.checked;
|
|
1665
|
+
_e(x), ee.current = x;
|
|
1666
|
+
for (const Q of Object.values(P.current)) Q.ctl.setTravelVisible(x);
|
|
1667
|
+
}
|
|
1668
|
+
function vn(o) {
|
|
1669
|
+
const x = o.target.checked;
|
|
1670
|
+
a((Q) => ({ ...Q, enable_support: x }));
|
|
1671
|
+
}
|
|
1672
|
+
const wn = !!Je(n, "enable_support"), kn = (((Pt = Bt.support_style) == null ? void 0 : Pt.enum_values) ?? []).map((o, x) => {
|
|
1673
|
+
var Q, he;
|
|
1674
|
+
return { value: o, label: ((he = (Q = Bt.support_style) == null ? void 0 : Q.enum_labels) == null ? void 0 : he[x]) ?? o };
|
|
1675
|
+
}), En = String(Je(n, "support_style") ?? "default"), [ct, Mn] = $(!1), dt = Number(Je(n, "support_threshold_angle")) || 30;
|
|
1676
|
+
Ve(() => {
|
|
1677
|
+
var o;
|
|
1678
|
+
(o = r.current) == null || o.setOverhang(ct && ne === "prepare" ? dt : null);
|
|
1679
|
+
}, [ct, dt, ne, de.length]);
|
|
1680
|
+
function pt() {
|
|
1681
|
+
Y(d.current.map((o) => ({ id: o.id, name: o.name, extruder: o.extruder, visible: o.visible !== !1 })));
|
|
1682
|
+
}
|
|
1683
|
+
function jn(o, x) {
|
|
1684
|
+
Oe((Q) => {
|
|
1685
|
+
var Be;
|
|
1686
|
+
const he = [...Q];
|
|
1687
|
+
return he[o] = x, Ze.current = he, (Be = r.current) == null || Be.recolorObjects(), he;
|
|
1688
|
+
});
|
|
1689
|
+
}
|
|
1690
|
+
function Cn() {
|
|
1691
|
+
Oe((o) => {
|
|
1692
|
+
if (o.length >= 4) return o;
|
|
1693
|
+
const x = ["#e0473b", "#3bb0e0", "#7ad14a"], Q = [...o, x[o.length - 1] || "#888888"];
|
|
1694
|
+
return Ze.current = Q, Q;
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1697
|
+
function Sn() {
|
|
1698
|
+
Oe((o) => {
|
|
1699
|
+
var Q;
|
|
1700
|
+
if (o.length <= 1) return o;
|
|
1701
|
+
const x = o.slice(0, -1);
|
|
1702
|
+
return Ze.current = x, d.current.forEach((he) => {
|
|
1703
|
+
var Be;
|
|
1704
|
+
(he.extruder || 1) > x.length && ((Be = r.current) == null || Be.setObjectExtruder(he.id, x.length));
|
|
1705
|
+
}), (Q = r.current) == null || Q.recolorObjects(), pt(), x;
|
|
1706
|
+
});
|
|
1707
|
+
}
|
|
1708
|
+
function Rn(o) {
|
|
1709
|
+
var Q;
|
|
1710
|
+
const x = d.current.find((he) => he.id === o);
|
|
1711
|
+
(Q = r.current) == null || Q.setObjectVisible(o, (x == null ? void 0 : x.visible) === !1), pt();
|
|
1712
|
+
}
|
|
1713
|
+
function Nt() {
|
|
1714
|
+
Ke(xe === "off" ? "enforcer" : "off");
|
|
1715
|
+
}
|
|
1716
|
+
const {
|
|
1717
|
+
duplicateSelected: ut,
|
|
1718
|
+
copySelected: At,
|
|
1719
|
+
pasteClipboard: _t,
|
|
1720
|
+
deleteSelected: mt,
|
|
1721
|
+
deleteAllObjects: Nn,
|
|
1722
|
+
splitSelected: ft,
|
|
1723
|
+
setGizmo: An
|
|
1724
|
+
} = _r({
|
|
1725
|
+
apiRef: r,
|
|
1726
|
+
objectsRef: d,
|
|
1727
|
+
clipboardRef: B,
|
|
1728
|
+
paintModeRef: _,
|
|
1729
|
+
setPaintMode: Ke,
|
|
1730
|
+
removeObject: Ct,
|
|
1731
|
+
refreshObjects: pt,
|
|
1732
|
+
setError: V,
|
|
1733
|
+
setSliceNotice: st
|
|
1734
|
+
}), _n = wr({
|
|
1735
|
+
add: () => {
|
|
1736
|
+
var o;
|
|
1737
|
+
return (o = Ae.current) == null ? void 0 : o.click();
|
|
1738
|
+
},
|
|
1739
|
+
remove: mt,
|
|
1740
|
+
removeAll: Nn,
|
|
1741
|
+
duplicate: ut,
|
|
1742
|
+
split: ft,
|
|
1743
|
+
placeOnBed: () => {
|
|
1744
|
+
var o;
|
|
1745
|
+
return (o = r.current) == null ? void 0 : o.placeOnBed();
|
|
1746
|
+
},
|
|
1747
|
+
objectCount: () => de.length
|
|
1748
|
+
});
|
|
1749
|
+
M.current = kr({
|
|
1750
|
+
slicing: je,
|
|
1751
|
+
isPreview: () => A.current === "preview",
|
|
1752
|
+
slice: it,
|
|
1753
|
+
copy: At,
|
|
1754
|
+
paste: _t,
|
|
1755
|
+
remove: mt,
|
|
1756
|
+
duplicate: ut,
|
|
1757
|
+
stepLayer: (o) => {
|
|
1758
|
+
const x = I.current + o;
|
|
1759
|
+
He(F ? x : te.current, x);
|
|
1760
|
+
},
|
|
1761
|
+
toggleSingleLayer: St,
|
|
1762
|
+
toggleTravel: () => Rt({ target: { checked: !ee.current } }),
|
|
1763
|
+
zoomAll: () => {
|
|
1764
|
+
var o;
|
|
1765
|
+
return (o = r.current) == null ? void 0 : o.frame();
|
|
1766
|
+
},
|
|
1767
|
+
zoomBed: () => {
|
|
1768
|
+
var o;
|
|
1769
|
+
return (o = r.current) == null ? void 0 : o.frameBed();
|
|
1770
|
+
},
|
|
1771
|
+
leavePreview: () => Me("prepare"),
|
|
1772
|
+
setGizmo: An,
|
|
1773
|
+
cancelTool: () => {
|
|
1774
|
+
var o;
|
|
1775
|
+
_.current !== "off" && Ke("off"), (o = r.current) == null || o.detachTransform();
|
|
1776
|
+
},
|
|
1777
|
+
rotateSelected: (o) => {
|
|
1778
|
+
var x;
|
|
1779
|
+
return (x = r.current) == null ? void 0 : x.rotateSelectedY(o);
|
|
1780
|
+
},
|
|
1781
|
+
nudgeSelected: (o, x) => {
|
|
1782
|
+
var Q;
|
|
1783
|
+
return (Q = r.current) == null ? void 0 : Q.nudgeSelected(o, x);
|
|
1784
|
+
},
|
|
1785
|
+
toggleHelp: () => ze((o) => !o)
|
|
1786
|
+
});
|
|
1787
|
+
const zn = $e.nozzle_diameter || Je(n, "nozzle_diameter") || "0.4";
|
|
1788
|
+
(Ot = (Lt = ot.current).invalidate) == null || Ot.call(Lt);
|
|
1789
|
+
const zt = Ee > 0 && /* @__PURE__ */ e.createElement(
|
|
1790
|
+
Zr,
|
|
1791
|
+
{
|
|
1792
|
+
viewType: et,
|
|
1793
|
+
onViewType: yn,
|
|
1794
|
+
layerCount: Ee,
|
|
1795
|
+
layerLo: rt,
|
|
1796
|
+
layerHi: s,
|
|
1797
|
+
segCount: q,
|
|
1798
|
+
singleLayer: F,
|
|
1799
|
+
onLayerLo: bn,
|
|
1800
|
+
onLayerHi: xn,
|
|
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,
|
|
1810
|
+
{
|
|
1811
|
+
showTabs: y,
|
|
1812
|
+
canvasMode: ne,
|
|
1813
|
+
onCanvasMode: Me,
|
|
1814
|
+
previewEnabled: Ee > 0,
|
|
1815
|
+
onOpen: () => {
|
|
1816
|
+
var o;
|
|
1817
|
+
return (o = Ae.current) == null ? void 0 : o.click();
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
), /* @__PURE__ */ e.createElement("div", { className: "app-body" }, y && ne === "prepare" && /* @__PURE__ */ e.createElement(
|
|
1821
|
+
Pr,
|
|
1822
|
+
{
|
|
1823
|
+
gizmoMode: D,
|
|
1824
|
+
paintMode: xe,
|
|
1825
|
+
onGizmo: (o) => {
|
|
1826
|
+
var x;
|
|
1827
|
+
Ke("off"), (x = r.current) == null || x.setMode(o);
|
|
1828
|
+
},
|
|
1829
|
+
onTogglePaint: Nt
|
|
1830
|
+
}
|
|
1831
|
+
), /* @__PURE__ */ e.createElement("div", { className: "viewport-col" }, /* @__PURE__ */ e.createElement(
|
|
1832
|
+
"div",
|
|
1833
|
+
{
|
|
1834
|
+
className: (y ? "vp-canvas" : "vp-canvas fail") + (Ne ? " drag-over" : ""),
|
|
1835
|
+
ref: $t,
|
|
1836
|
+
onDrop: un,
|
|
1837
|
+
onDragOver: mn,
|
|
1838
|
+
onDragLeave: fn,
|
|
1839
|
+
"data-testid": "drop-zone"
|
|
1840
|
+
},
|
|
1841
|
+
!y && /* @__PURE__ */ e.createElement("div", { className: "vp-fallback" }, "⚠ ", oe),
|
|
1842
|
+
y && de.length === 0 && ne !== "preview" && /* @__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" }, ht), /* @__PURE__ */ e.createElement("button", { className: "eh-btn", onClick: () => {
|
|
1843
|
+
var o;
|
|
1844
|
+
return (o = Ae.current) == null ? void 0 : o.click();
|
|
1845
|
+
}, "data-testid": "empty-pick", title: `Pick a ${ht} file (multiple allowed)` }, "Choose file")),
|
|
1846
|
+
Ne && /* @__PURE__ */ e.createElement("div", { className: "drop-overlay", "data-testid": "drop-overlay" }, "Drop here (STL/OBJ/3MF/AMF/PLY)"),
|
|
1847
|
+
Ie && /* @__PURE__ */ e.createElement(
|
|
1848
|
+
Or,
|
|
1849
|
+
{
|
|
1850
|
+
menu: Ie,
|
|
1851
|
+
onClose: () => We(null),
|
|
1852
|
+
canPaste: !!B.current,
|
|
1853
|
+
actions: {
|
|
1854
|
+
duplicate: ut,
|
|
1855
|
+
copy: At,
|
|
1856
|
+
split: ft,
|
|
1857
|
+
placeOnBed: () => {
|
|
1858
|
+
var o;
|
|
1859
|
+
return (o = r.current) == null ? void 0 : o.placeOnBed();
|
|
1860
|
+
},
|
|
1861
|
+
remove: mt,
|
|
1862
|
+
openFile: () => {
|
|
1863
|
+
var o;
|
|
1864
|
+
return (o = Ae.current) == null ? void 0 : o.click();
|
|
1865
|
+
},
|
|
1866
|
+
paste: _t,
|
|
1867
|
+
zoomAll: () => {
|
|
1868
|
+
var o;
|
|
1869
|
+
return (o = r.current) == null ? void 0 : o.frame();
|
|
1870
|
+
},
|
|
1871
|
+
zoomBed: () => {
|
|
1872
|
+
var o;
|
|
1873
|
+
return (o = r.current) == null ? void 0 : o.frameBed();
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
),
|
|
1878
|
+
ke && /* @__PURE__ */ e.createElement(Tr, { onClose: () => ze(!1) })
|
|
1879
|
+
), y && ne === "prepare" && /* @__PURE__ */ e.createElement(Lr, { tools: _n }), y && ne === "prepare" && xe !== "off" && /* @__PURE__ */ e.createElement(
|
|
1880
|
+
Br,
|
|
1881
|
+
{
|
|
1882
|
+
paintMode: xe,
|
|
1883
|
+
onPaintMode: Ke,
|
|
1884
|
+
onClear: rn,
|
|
1885
|
+
brushRadius: Ue,
|
|
1886
|
+
paintCounts: Ut,
|
|
1887
|
+
onBrushRadius: (o) => {
|
|
1888
|
+
yt(o), G.current = o;
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
), y && ne === "preview" && p && /* @__PURE__ */ e.createElement("div", { className: "stats-card", "data-testid": "slice-stats" }, Pn), y && /* @__PURE__ */ e.createElement(
|
|
1892
|
+
Dr,
|
|
1893
|
+
{
|
|
1894
|
+
plateCount: ie,
|
|
1895
|
+
selectedPlate: se,
|
|
1896
|
+
maxPlates: Vt,
|
|
1897
|
+
onSelect: dn,
|
|
1898
|
+
onAdd: sn,
|
|
1899
|
+
onDelete: cn
|
|
1900
|
+
}
|
|
1901
|
+
), y && /* @__PURE__ */ e.createElement("div", { className: "vp-status", "data-testid": "vp-status" }, oe)), y && /* @__PURE__ */ e.createElement("aside", { className: "sidebar" }, /* @__PURE__ */ e.createElement("div", { className: "sidebar-scroll" }, /* @__PURE__ */ e.createElement(
|
|
1902
|
+
Gr,
|
|
1903
|
+
{
|
|
1904
|
+
bedWidth: $e.bed_width,
|
|
1905
|
+
bedDepth: $e.bed_depth,
|
|
1906
|
+
nozzleDia: zn,
|
|
1907
|
+
onBedSize: hn,
|
|
1908
|
+
settings: n,
|
|
1909
|
+
setSettings: a,
|
|
1910
|
+
motionPanel: l
|
|
1911
|
+
}
|
|
1912
|
+
), /* @__PURE__ */ e.createElement(Ur, { colors: De, onColor: jn, onAdd: Cn, onRemove: Sn }), de.length > 0 && /* @__PURE__ */ e.createElement(
|
|
1913
|
+
$r,
|
|
1914
|
+
{
|
|
1915
|
+
objects: de,
|
|
1916
|
+
extruderColors: De,
|
|
1917
|
+
onToggleVisible: Rn,
|
|
1918
|
+
onExtruder: gn,
|
|
1919
|
+
onSplit: (o) => {
|
|
1920
|
+
var x;
|
|
1921
|
+
(x = r.current) == null || x.selectObject(o), ft();
|
|
1922
|
+
},
|
|
1923
|
+
onRemove: Ct,
|
|
1924
|
+
supportOn: wn,
|
|
1925
|
+
onToggleSupport: vn,
|
|
1926
|
+
overhangOn: ct,
|
|
1927
|
+
onToggleOverhang: (o) => Mn(o.target.checked),
|
|
1928
|
+
overhangAngle: dt,
|
|
1929
|
+
paintMode: xe,
|
|
1930
|
+
onTogglePaint: Nt,
|
|
1931
|
+
supportStyle: En,
|
|
1932
|
+
supportStyles: kn,
|
|
1933
|
+
onSupportStyle: (o) => a((x) => ({ ...x, support_style: o })),
|
|
1934
|
+
wipeTowerReal: Te,
|
|
1935
|
+
onToggleWipeTower: (o) => X(o.target.checked)
|
|
1936
|
+
}
|
|
1937
|
+
), C && /* @__PURE__ */ e.createElement("div", { className: "slice-warn side-warn" }, "⚠ ", C), wt && /* @__PURE__ */ e.createElement("div", { className: "slice-warn side-warn", "data-testid": "slice-notice" }, "ℹ ", wt), S && /* @__PURE__ */ e.createElement("div", { className: "slice-err side-warn", "data-testid": "slice-err" }, S), kt && /* @__PURE__ */ e.createElement("button", { className: "slice-btn", "data-testid": "downgrade-retry", onClick: ln, title: "Simplify the infill and lower its density to reduce memory pressure, then retry" }, "Simplified retry (simple infill, economy mode)"), ne === "preview" && zt && /* @__PURE__ */ e.createElement("section", { className: "side-card" }, /* @__PURE__ */ e.createElement("div", { className: "sc-head" }, "🎚 Preview"), zt), /* @__PURE__ */ e.createElement("section", { className: "side-card process-card", "data-testid": "process-section" }, /* @__PURE__ */ e.createElement("div", { className: "sc-head" }, "⚙ Process"), c)), /* @__PURE__ */ e.createElement(
|
|
1938
|
+
Hr,
|
|
1939
|
+
{
|
|
1940
|
+
autoSlice: ye,
|
|
1941
|
+
onAutoSlice: Re,
|
|
1942
|
+
slicing: je,
|
|
1943
|
+
progress: Se,
|
|
1944
|
+
plateCount: ie,
|
|
1945
|
+
selectedPlate: se,
|
|
1946
|
+
sliceMenuOpen: J,
|
|
1947
|
+
onSliceMenu: () => ce((o) => !o),
|
|
1948
|
+
slicedPlateCount: Fe,
|
|
1949
|
+
canSlice: de.length > 0,
|
|
1950
|
+
onSlice: it,
|
|
1951
|
+
onCancel: jt,
|
|
1952
|
+
onExportAll: an,
|
|
1953
|
+
gcodeUrl: fe
|
|
1954
|
+
}
|
|
1955
|
+
)))));
|
|
1105
1956
|
}
|
|
1106
1957
|
export {
|
|
1107
|
-
|
|
1958
|
+
no as default
|
|
1108
1959
|
};
|