diff --git a/mods/bambu/bambu.js b/mods/bambu/bambu.js index 3b1a3bd6..53117cc3 100644 --- a/mods/bambu/bambu.js +++ b/mods/bambu/bambu.js @@ -37,7 +37,8 @@ self.kiri.load(api => { let { serial, message, error } = data; if (error) { console.log({ serial, error }); - printer_status(`error: ${error}`); + api.alerts.show(`Bambu Error: ${error}`, 3); + // printer_status(`error: ${error}`); } else if (serial) { let rec = status[serial] = deepMerge(status[serial] || {}, message); if (selected?.rec.serial === serial) { @@ -176,9 +177,14 @@ self.kiri.load(api => { $('bbl_bed_target').value = bed_target_temper?.toFixed(1) ?? ''; if (files) { h.bind($('bbl_files'), files.map(file => { + let name = file.name + .toLowerCase() + .replace('.gcode','') + .replace('.3mf',''); return h.option({ - _: file.name || file, - style: "max-width: 20em" + _: name, + style: "max-width: 20em", + value:`${file.path}${file.name}` }); })); rec.files = undefined; @@ -196,7 +202,7 @@ self.kiri.load(api => { $('bbl_status').value = msg; } - function render_list() { + function render_list(to) { let list = Object.keys(printers).map(name => { return h.option({ _: name, value: name }) }); @@ -204,7 +210,7 @@ self.kiri.load(api => { h.option({ _: '', value: '' }), ...list ] - h.bind(select, list); + h.bind(to || select, list); } function monitor_start(rec) { @@ -421,26 +427,35 @@ self.kiri.load(api => { } }); - function sendok(params = {}) { - host = password = serial = amsmap = undefined; - const { settings } = params; - const ams = settings.device?.gcodePre.filter(line => line.indexOf(defams) === 0)[0]; - if (ams) { - try { - amsmap = ams.substring(defams.length).trim().replaceAll(' ',''); - } catch (e) { - console.log({ invalid_ams_map: ams }); - } + function prep_export(gen3mf, gcode, info, settings) { + if (!settings.device.extras?.bbl) { + $('bambu-output').style.display = 'none'; + return; } - const feature = settings.device?.gcodePre.filter(line => line.indexOf(defhost) === 0)[0]; - if (feature) { - [ host, password, serial ] = feature.substring(defhost.length).split(' ').map(v => v.trim()); - console.log('BAMBU', { host , password, serial }); - if (host && password) { - return true; - } + printers = settings.device.extras.bbl; + let devlist = $('print-bambu-device'); + render_list(devlist); + $('bambu-output').style.display = 'flex'; + $('print-bambu').onclick = function() { + gen3mf(zip => send(`${$('print-filename').value}.3mf`, zip)); } - return false; + devlist.onchange = () => { + let info = printers[devlist.value]; + console.log({ selected: devlist.value, info }); + host = info.host; + serial = info.serial; + password = info.code; + $('print-bambu').disabled = (host && serial && password) ? false : true; + const ams = settings.device?.gcodePre.filter(line => line.indexOf(defams) === 0)[0]; + if (ams) { + try { + amsmap = ams.substring(defams.length).trim().replaceAll(' ',''); + } catch (e) { + console.log({ invalid_ams_map: ams }); + } + } + console.log({ bambu: host, serial, amsmap }); + }; } function send(filename, gcode) { @@ -479,5 +494,5 @@ self.kiri.load(api => { setInterval(monitor_keepalive, 5000); - api.bambu = { send, sendok, amsmap }; + api.bambu = { send, amsmap, prep_export }; }); diff --git a/mods/bambu/init.js b/mods/bambu/init.js index 42e8793f..d7639ed0 100644 --- a/mods/bambu/init.js +++ b/mods/bambu/init.js @@ -145,8 +145,16 @@ module.exports = async (server) => { async function ftp_list(args = {}) { const client = await ftp_open(args); const list = []; - try { list.push(...(await client.list())) } catch (e) { } - try { list.push(...(await client.list("/cache"))) } catch (e) { } + try { + let files = await client.list(); + files.forEach(file => file.path = "/"); + list.push(...files); + } catch (e) { } + try { + let files = await client.list("/cache"); + files.forEach(file => file.path = "/cache/"); + list.push(...files); + } catch (e) { } client.close(); return list; } @@ -193,7 +201,8 @@ module.exports = async (server) => { const { host, password, filename, serial, ams } = query; const ams_mapping = ams ? ams.split(',').map(v => parseInt(v)) : undefined; const mqtt_conn = serial ? get_mqtt(host, password, serial, message => { - util.log('mqtt_recv', JSON.parse(message.toString())); + util.log('mqtt_recv', message); + // util.log('mqtt_recv', JSON.parse(message.toString())); }) : undefined; ftp_send({ host, password, filename, data }) .then(() => { @@ -271,6 +280,7 @@ module.exports = async (server) => { .filter(file => file.name.toLowerCase().endsWith(".3mf")) .map(file => { return { + path: file.path, name: file.name, size: file.size, date: file.rawModifiedAt diff --git a/src/geo/polygon.js b/src/geo/polygon.js index e48a63f2..8e722fca 100644 --- a/src/geo/polygon.js +++ b/src/geo/polygon.js @@ -2037,7 +2037,7 @@ class Polygon { tree = new PolyTree(), sp1 = this.toClipper(), sp2 = poly.toClipper(), - minarea = min >= 0 ? min : 0.1; + minarea = min ?? 0.1; clip.AddPaths(sp1, PathSubject, true); clip.AddPaths(sp2, PathClip, true); diff --git a/src/geo/polygons.js b/src/geo/polygons.js index 57d1ce77..cf6c411f 100644 --- a/src/geo/polygons.js +++ b/src/geo/polygons.js @@ -431,7 +431,7 @@ function subtract(setA, setB, outA, outB, z, minArea, opt = {}) { let lpre = length(polys); if (opt.wasm && geo.wasm) { - let min = minarea || 0.01; + let min = minarea ?? 0.01; // let deepLength = polys.map(p => p.deepLength).reduce((a,v) => a+v); // if (deepLength < 15000) try { @@ -632,7 +632,7 @@ function offset(polys, dist, opts = {}) { let coff = new ClipperOffset(opts.miter, opts.arc), tree = new PolyTree(); - // setup offset + // setup offset for (let poly of polys) { // convert to clipper format poly = poly.toClipper(); diff --git a/src/kiri-mode/cam/client.js b/src/kiri-mode/cam/client.js index e6abff07..2dc4032d 100644 --- a/src/kiri-mode/cam/client.js +++ b/src/kiri-mode/cam/client.js @@ -1467,6 +1467,7 @@ CAM.init = function(kiri, api) { offover: 'camTraceOffOver', dogbone: 'camTraceDogbone', revbone: 'camTraceDogbone', + merge: 'camTraceMerge', select: 'camTraceMode' }).inputs = { tool: UC.newSelect(LANG.cc_tool, {}, "tools"), @@ -1483,6 +1484,7 @@ CAM.init = function(kiri, api) { thru: UC.newInput(LANG.cc_thru_s, {title:LANG.cc_thru_l, convert:UC.toFloat, units:true}), offover: UC.newInput(LANG.cc_offd_s, {title:LANG.cc_offd_l, convert:UC.toFloat, units:true, show:() => poppedRec.offset !== "none"}), sep: UC.newBlank({class:"pop-sep", modes:MCAM, xshow:zDogSep}), + merge: UC.newBoolean(LANG.co_merg_s, undefined, {title:LANG.co_merg_l}), bottom: UC.newBoolean(LANG.cf_botm_s, undefined, {title:LANG.cf_botm_l, show:(op,conf) => conf.process.camZBottom}), dogbone: UC.newBoolean(LANG.co_dogb_s, undefined, {title:LANG.co_dogb_l, show:canDogBones}), revbone: UC.newBoolean(LANG.co_dogr_s, undefined, {title:LANG.co_dogr_l, show:canDogBonesRev}), diff --git a/src/kiri-mode/cam/driver.js b/src/kiri-mode/cam/driver.js index 5f6d498c..fd50abc1 100644 --- a/src/kiri-mode/cam/driver.js +++ b/src/kiri-mode/cam/driver.js @@ -69,6 +69,7 @@ kiri.load(api => { kiri.client.send("cam_traces", { settings, single }, output => { const ids = []; kiri.codec.decode(output).forEach(rec => { +console.log({ rec }); ids.push(rec.id); widgets[rec.id].traces = rec.traces; }); diff --git a/src/kiri-mode/cam/ops.js b/src/kiri-mode/cam/ops.js index 56448fea..05d014a7 100644 --- a/src/kiri-mode/cam/ops.js +++ b/src/kiri-mode/cam/ops.js @@ -1090,6 +1090,7 @@ class OpTrace extends CamOp { poly2polyEmit(polys, newPoint(0,0,0), (poly, index, count, spoint) => { routed.push(poly); }); + let output = []; for (let poly of POLY.nest(routed)) { let offdist = offset !== 'none' ? offover : 0; if (!offdist) @@ -1116,15 +1117,24 @@ class OpTrace extends CamOp { zto -= zThru; } for (let z of base.util.lerp(zTop, zto, down)) { - followZ(pi.clone().setZ(z)); + output.push(pi.clone().setZ(z)); } } else { if (thru) { pi.setZ(pi.getZ() - thru); } - followZ(pi); + output.push(pi); } } + // merge overlapping output to prevent overcuts + if (op.merge) { + let nest = POLY.nest(output); + let union = POLY.union(nest, 0, true); + output = POLY.flatten(union, [], true); + } + for (let poly of output) { + followZ(poly); + } break; case "clear": const zbo = widget.track.top - widget.track.box.d; diff --git a/src/kiri-mode/cam/slice.js b/src/kiri-mode/cam/slice.js index c33402fc..df8612de 100644 --- a/src/kiri-mode/cam/slice.js +++ b/src/kiri-mode/cam/slice.js @@ -365,7 +365,7 @@ CAM.traces = async function(settings, widget, single) { let trace = traces[i]; let dz = Math.abs(z - trace.getZ()); // only compare polys farther apart in Z - if (dz < 0.01) { + if (dz > 0.01) { continue; } // do not add duplicates diff --git a/src/kiri/export.js b/src/kiri/export.js index 65c1672b..e08b34e6 100644 --- a/src/kiri/export.js +++ b/src/kiri/export.js @@ -477,8 +477,7 @@ function exportGCodeDialog(gcode, sections, info, names) { $('code-preview-head').style.display = preview ? '' : 'none'; $('code-preview').style.display = preview ? '' : 'none'; $('print-download').onclick = download; - $('print-filament-head').style.display = fdm ? '' : 'none'; - $('print-filament-info').style.display = fdm ? '' : 'none'; + $('print-filament').style.display = fdm ? '' : 'none'; $('print-filename').value = filename; $('print-filesize').value = util.comma(info.bytes); $('print-filament').value = Math.round(info.distance); @@ -523,10 +522,10 @@ function exportGCodeDialog(gcode, sections, info, names) { download3MF.onclick = function() { gen3mf(zip => api.util.download(zip, `${$('print-filename').value}.3mf`)); }; - let downloadBambu = $('print-bambu'); - downloadBambu.style.display = api.bambu && api.bambu.sendok({ gcode, info, settings }) ? 'flex' : 'none'; - downloadBambu.onclick = function() { - gen3mf(zip => api.bambu.send(`${$('print-filename').value}.3mf`, zip)); + + // present bambu print options when selected device is bambu + if (api.bambu) { + api.bambu.prep_export(gen3mf, gcode, info, settings); } function gen3mf(then) { diff --git a/web/kiri/index.css b/web/kiri/index.css index cb9473d6..ac9c4fdc 100644 --- a/web/kiri/index.css +++ b/web/kiri/index.css @@ -107,7 +107,7 @@ button { cursor: pointer; text-transform: capitalize; } -button:hover { +button:not([disabled]):hover { background-color: var(--main-color); color: white; } @@ -118,6 +118,9 @@ button[load] { button[del] { margin-left: 5px; } +button[disabled] { + color: #999; +} input { background-color: #f8f8ff; margin-bottom: 1px; @@ -225,6 +228,9 @@ details[open] > summary::after { } /** dark conversion */ +.dark button[disabled] { + color: #888; +} .dark input[disabled] { border-color: #666; background-color: #444; @@ -250,7 +256,7 @@ details[open] > summary::after { background-color: #555; border: 1px solid #777; } -button:hover { +.dark button:not([disabled]):hover { background-color: var(--blue-2); color: black; } @@ -670,6 +676,9 @@ button:hover { .basis-50 { flex-basis: 50%; } +.grow0 { + flex-grow: 0 !important; +} .grow { flex-grow: 1; } @@ -1633,7 +1642,7 @@ button:hover { background-color: rgba(255,255,255,0.5); border: 1px solid #bbb; border-radius: 3px; - padding: 20px 10px 10px 10px; + padding: 12px 10px 10px 10px; } .mod-print .box select { min-width: 10em; @@ -1695,9 +1704,10 @@ button:hover { display: none; } #code-preview-textarea { - width: 40em; - height: 12em; - font-size: smaller; + min-width: 50em; + width: 100%; + height: 7em; + font-size: x-small; font-family: Courier,monospace; white-space: nowrap; resize: none; diff --git a/web/kiri/index.html b/web/kiri/index.html index fbd1379c..a8c3dfe4 100644 --- a/web/kiri/index.html +++ b/web/kiri/index.html @@ -583,19 +583,25 @@
-
- +
+
+
+ + + +
diff --git a/web/kiri/lang/en.js b/web/kiri/lang/en.js index 9ca5b021..23a15808 100644 --- a/web/kiri/lang/en.js +++ b/web/kiri/lang/en.js @@ -521,6 +521,8 @@ self.kiri.lang['en-us'] = { // CNC OUTLINE co_menu: "outline", + co_merg_s: "merge overlap", + co_merg_l: ["merge overlapping lines to prevent overcutting into adjacent solids"], co_dogb_s: "dogbones", co_dogb_l: ["insert dogbone cuts","into inside corners"], co_dogr_s: "reverse bones",