From 90cf2b038e18aa03057a7b372bc146f372470cc1 Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Fri, 11 Feb 2022 11:50:34 -0500 Subject: [PATCH] make cli a more fully featured command line utility refs #199 --- src/cli/kiri-fdm-device.json | 64 ++++++ src/cli/kiri-fdm-process.json | 70 ++++++ src/cli/kiri-source.json | 52 +++++ src/kiri/cli.js | 397 +++++++++++++--------------------- src/kiri/widget.js | 4 + 5 files changed, 340 insertions(+), 247 deletions(-) create mode 100644 src/cli/kiri-fdm-device.json create mode 100644 src/cli/kiri-fdm-process.json create mode 100644 src/cli/kiri-source.json diff --git a/src/cli/kiri-fdm-device.json b/src/cli/kiri-fdm-device.json new file mode 100644 index 00000000..f246ecbf --- /dev/null +++ b/src/cli/kiri-fdm-device.json @@ -0,0 +1,64 @@ +{ + "noclone":false, + "mode":"FDM", + "internal":0, + "imageURL":"", + "imageScale":0.75, + "imageAnchor":0, + "bedHeight":2.5, + "bedWidth":220, + "bedDepth":220, + "bedRound":false, + "bedBelt":false, + "maxHeight":300, + "originCenter":false, + "extrudeAbs":true, + "spindleMax":0, + "gcodeFan":[ "M106 S{fan_speed}" ], + "gcodeTrack":[], + "gcodeLayer":[], + "gcodePre":[ + "M107 ; turn off filament cooling fan", + "G90 ; set absolute positioning mode", + "M82 ; set absolute positioning for extruder", + "M104 S{temp} T{tool} ; set extruder temperature", + "M140 S{bed_temp} T{tool} ; set bed temperature", + "G28 ; home axes", + "G92 X0 Y0 Z0 E0 ; reset all axes positions", + "G1 X0 Y0 Z0.25 F180 ; move XY to 0,0 and Z 0.25mm over bed", + "G92 E0 ; zero the extruded", + "M190 S{bed_temp} T{tool} ; wait for bed to reach target temp", + "M109 S{temp} T{tool} ; wait for extruder to reach target temp", + "G92 E0 ; zero the extruded", + "G1 F225 ; set feed speed" + ], + "gcodePost":[ + "M107 ; turn off filament cooling fan", + "M104 S0 T{tool} ; turn off right extruder", + "M140 S0 T{tool} ; turn off bed", + "G1 X0 Y300 F1200 ; end move", + "M84 ; disable stepper motors" + ], + "gcodeProc":"", + "gcodePause":[], + "gcodeDwell":[], + "gcodeSpindle":[], + "gcodeChange":[], + "gcodeFExt":"gcode", + "gcodeSpace":true, + "gcodeStrip":false, + "gcodeLaserOn":[], + "gcodeLaserOff":[], + "extruders":[ + { + "extFilament":1.75, + "extNozzle":0.4, + "extSelect":[ "T0" ], + "extDeselect":[], + "extOffsetX":0, + "extOffsetY":0 + } + ], + "new":false, + "deviceName":"Creality.Ender.3" +} diff --git a/src/cli/kiri-fdm-process.json b/src/cli/kiri-fdm-process.json new file mode 100644 index 00000000..20eb1da9 --- /dev/null +++ b/src/cli/kiri-fdm-process.json @@ -0,0 +1,70 @@ +{ + "sName":"Ender3_test", + "sliceHeight":0.25, + "sliceShells":3, + "sliceShellOrder":"in-out", + "sliceLayerStart":"last", + "sliceFillAngle":45, + "sliceFillOverlap":0.3, + "sliceFillSparse":0.2, + "sliceFillType":"gyroid", + "sliceAdaptive":false, + "sliceMinHeight":0, + "sliceSupportDensity":0.25, + "sliceSupportOffset":0.4, + "sliceSupportGap":1, + "sliceSupportSize":6, + "sliceSupportArea":1, + "sliceSupportExtra":0, + "sliceSupportAngle":50, + "sliceSupportNozzle":0, + "sliceSolidMinArea":1, + "sliceSolidLayers":3, + "sliceBottomLayers":3, + "sliceTopLayers":3, + "firstLayerRate":10, + "firstLayerPrintMult":1.15, + "firstLayerYOffset":0, + "firstLayerBrim":0, + "firstLayerBeltLead":3, + "outputTemp":210, + "outputBedTemp":60, + "outputFeedrate":50, + "outputFinishrate":50, + "outputSeekrate":80, + "outputShellMult":1.25, + "outputFillMult":1.25, + "outputSparseMult":1.25, + "outputRetractDist":4, + "outputRetractSpeed":30, + "outputRetractDwell":30, + "outputShortPoly":100, + "outputMinSpeed":10, + "outputCoastDist":0.1, + "outputLayerRetract":true, + "detectThinWalls":true, + "zHopDistance":0, + "antiBacklash":0, + "outputOriginCenter":false, + "sliceFillRate":0, + "sliceSupportEnable":false, + "firstSliceHeight":0.25, + "firstLayerFillRate":35, + "firstLayerLineMult":1, + "firstLayerNozzleTemp":0, + "firstLayerBedTemp":0, + "firstLayerBrimTrig":0, + "outputRaft":false, + "outputRaftSpacing":0.2, + "outputRetractWipe":0, + "outputBrimCount":2, + "outputBrimOffset":2, + "outputLoopLayers":null, + "outputInvertX":false, + "outputInvertY":false, + "arcTolerance":0, + "gcodePause":"", + "ranges":[], + "firstLayerFanSpeed":0, + "outputFanSpeed":255 +} diff --git a/src/cli/kiri-source.json b/src/cli/kiri-source.json new file mode 100644 index 00000000..5b98a0f1 --- /dev/null +++ b/src/cli/kiri-source.json @@ -0,0 +1,52 @@ +[ + "main/gapp", + "moto/license", + "main/kiri", + "ext/three", + "ext/pngjs", + "ext/jszip", + "ext/clip2", + "ext/earcut", + "add/array", + "add/three", + "add/class", + "geo/base", + "geo/point", + "geo/points", + "geo/slope", + "geo/line", + "geo/bounds", + "geo/polygons", + "geo/polygon", + "geo/gyroid", + "kiri/conf", + "kiri/pack", + "kiri/client", + "kiri/engine", + "kiri/slice", + "kiri/slicer", + "kiri/layers", + "kiri-mode/fdm/fill", + "kiri-mode/fdm/driver", + "kiri-mode/fdm/slice", + "kiri-mode/fdm/prepare", + "kiri-mode/fdm/export", + "kiri-mode/sla/driver", + "kiri-mode/sla/slice", + "kiri-mode/sla/export", + "kiri-mode/cam/driver", + "kiri-mode/cam/slicer", + "kiri-mode/cam/ops", + "kiri-mode/cam/tool", + "kiri-mode/cam/topo", + "kiri-mode/cam/slice", + "kiri-mode/cam/prepare", + "kiri-mode/cam/export", + "kiri-mode/cam/animate", + "kiri-mode/laser/driver", + "kiri/widget", + "kiri/print", + "kiri/codec", + "kiri/worker", + "load/stl" +] diff --git a/src/kiri/cli.js b/src/kiri/cli.js index 5d7eede9..e360ef1a 100644 --- a/src/kiri/cli.js +++ b/src/kiri/cli.js @@ -1,60 +1,54 @@ /** example of how to use Kiri:Moto's slicer engine from the command-line */ let fs = require('fs'); let args = process.argv.slice(2); -let dir = args[0] || "."; -let files = [ - "main/gapp", - "moto/license", - "main/kiri", - "ext/three", - "ext/pngjs", - "ext/jszip", - "ext/clip2", - "ext/earcut", - "add/array", - "add/three", - "add/class", - "geo/base", - "geo/point", - "geo/points", - "geo/slope", - "geo/line", - "geo/bounds", - "geo/polygons", - "geo/polygon", - "geo/gyroid", - "kiri/conf", - "kiri/pack", - "kiri/client", - "kiri/engine", - "kiri/slice", - "kiri/slicer", - "kiri/layers", - "kiri-mode/fdm/fill", - "kiri-mode/fdm/driver", - "kiri-mode/fdm/slice", - "kiri-mode/fdm/prepare", - "kiri-mode/fdm/export", - "kiri-mode/sla/driver", - "kiri-mode/sla/slice", - "kiri-mode/sla/export", - "kiri-mode/cam/driver", - "kiri-mode/cam/slicer", - "kiri-mode/cam/ops", - "kiri-mode/cam/tool", - "kiri-mode/cam/topo", - "kiri-mode/cam/slice", - "kiri-mode/cam/prepare", - "kiri-mode/cam/export", - "kiri-mode/cam/animate", - "kiri-mode/laser/driver", - "kiri/widget", - "kiri/print", - "kiri/codec", - "kiri/worker", - "load/stl" -].map(p => `${dir}/src/${p}.js`); +let opts = { + dir: ".", + output: "-", + model: "/web/obj/cube.stl", + source: "/src/cli/kiri-source.json", + process: "/src/cli/kiri-fdm-process.json", + device: "/src/cli/kiri-fdm-device.json", +}; +for (let i=0; i ", + " --verbose | enable verbose logging", + " --dir=[dir] | root directory for file paths (default: '.')", + " --model=[file] | model file to load (or last parameter)", + " --source=[file] | source file list (defaults to kiri engine)", + " --device=[file] | device definition file (json)", + " --process=[file] | process definition file (json)", + " --output=[file] | gcode output to file or '-' for stdout", + " --position=x,y,z | move loaded model to position x,y,z", + " --rotate=x,y,z | rotate loaded model x,y,z radians", + " --scale=x,y,z | scale loaded model in x,y,z", + " --move=x,y,z | move loaded model x,y,z millimeters" + ].join("\r\n")); + return; +} +let { dir, verbose, model, output, position, move, scale, rotate } = opts; let exports_save = exports, navigator = { userAgent: "" }, module_save = module, @@ -72,11 +66,20 @@ let exports_save = exports, }; // fake fetch for worker to get wasm, if needed -let fetch = function(url) { - console.log({fake_fetch: url}); +let fetch = function(url, opts = {}) { + if (verbose) console.log({fetch: url}); let buf = fs.readFileSync(dir + url); return new Promise((resolve, reject) => { resolve(new Promise((resolve, reject) => { + if (opts.format === 'string') { + return resolve(buf.toString()); + } + if (opts.format === 'buffer') { + return resolve(buf); + } + if (opts.format === 'eval') { + return resolve(eval('(' + buf + ')')); + } resolve({ arrayBuffer: function() { return buf; @@ -89,7 +92,7 @@ let fetch = function(url) { // imitate worker process class Worker { constructor(url) { - console.log({fake_worker: url}); + if (verbose) console.log({worker: url}); } postMessage(msg) { @@ -118,197 +121,97 @@ function btoa(b) { return Buffer.from(b, 'base64').toString(); } -for (let file of files) { - let isPNG = file.indexOf("/pngjs") > 0; - let isClip = file.indexOf("/clip") > 0; - let isEarcut = file.indexOf("/earcut") > 0; - let isTHREE = file.indexOf("/three") > 0; - if (isTHREE) { - // THREE.js kung-fu fake-out - exports = {}; - } - let swapMod = isEarcut; - if (swapMod) { - module = { exports: {} }; - } - let clearMod = isPNG || isClip; - if (clearMod) { - module = undefined; - } - try { - console.log(`loading ... ${dir}/${file}`); - eval(fs.readFileSync(dir + "/" + file).toString()); - } catch (e) { - throw e; - } - if (isClip) { - ClipperLib = self.ClipperLib; - } - if (isTHREE) { - Object.assign(THREE, exports); - // restore exports after faking out THREE.js - exports = exports_save; - } - if (isEarcut) { - self.earcut = module.exports; - } - if (clearMod || swapMod) { - module = module_save; +async function run() { + let files = await fetch(opts.source, { format: "eval" } ); + let device = await fetch(opts.device, { format: "eval" } ); + let process = await fetch(opts.process, { format: "eval" } ); + + for (let file of files.map(p => `${dir}/src/${p}.js`)) { + let isPNG = file.indexOf("/pngjs") > 0; + let isClip = file.indexOf("/clip") > 0; + let isEarcut = file.indexOf("/earcut") > 0; + let isTHREE = file.indexOf("/three") > 0; + if (isTHREE) { + // THREE.js kung-fu fake-out + exports = {}; + } + let swapMod = isEarcut; + if (swapMod) { + module = { exports: {} }; + } + let clearMod = isPNG || isClip; + if (clearMod) { + module = undefined; + } + try { + if (verbose) console.log(`loading ... ${dir}/${file}`); + eval(fs.readFileSync(dir + "/" + file).toString()); + } catch (e) { + throw e; + } + if (isClip) { + ClipperLib = self.ClipperLib; + } + if (isTHREE) { + Object.assign(THREE, exports); + // restore exports after faking out THREE.js + exports = exports_save; + } + if (isEarcut) { + self.earcut = module.exports; + } + if (clearMod || swapMod) { + module = module_save; + } } + + let { kiri, moto, load } = self; + + console.log({version: kiri.version}); + + let engine = kiri.newEngine(); + let data = await fetch(model) + let buf = data.arrayBuffer().buffer; + + return engine.parse(buf) + .then(data => { if (verbose) console.log({loaded: data}) }) + .then(() => { + if (position) { + let [ x, y, z ] = position.split(',').map(v => parseFloat(v || 0)); + if (verbose) console.log('moveTo', {x, y, z}); + engine.moveTo(x,y,z); + } + if (move) { + let [ x, y, z ] = move.split(',').map(v => parseFloat(v || 0)); + if (verbose) console.log('move', {x, y, z}); + engine.move(x,y,z); + } + if (scale) { + let [ x, y, z ] = scale.split(',').map(v => parseFloat(v || 0)); + if (verbose) console.log('scale', {x, y, z}); + engine.scale(x,y,z); + } + if (rotate) { + let [ x, y, z ] = rotate.split(',').map(v => parseFloat(v || 0)); + if (verbose) console.log('rotate', {x, y, z}); + engine.rotate(x,y,z); + } + }) + .then(() => engine.setProcess(process)) + .then(() => engine.setDevice(device)) + .then(eng => eng.slice()) + .then(eng => eng.prepare()) + .then(eng => engine.export()) + .then(gcode => { + if (output === '-') { + console.log({gcode}); + } else { + fs.writeFileSync(output, gcode); + } + }) + .catch(error => { + console.log({error}); + }); } -let { kiri, moto, load } = self; -let engine = kiri.newEngine(); - -fetch('/web/obj/cube.stl').then(data => { - console.log({version: kiri.version}); - let buf = data.arrayBuffer().buffer; - engine.parse(buf) - .then(data => { - console.log({loaded: data}); - }) - .then(() => engine.moveTo(1,1,1)) - .then(() => engine.setProcess({ - "sName":"Ender3_test", - "sliceHeight":0.25, - "sliceShells":3, - "sliceShellOrder":"in-out", - "sliceLayerStart":"last", - "sliceFillAngle":45, - "sliceFillOverlap":0.3, - "sliceFillSparse":0.2, - "sliceFillType":"gyroid", - "sliceAdaptive":false, - "sliceMinHeight":0, - "sliceSupportDensity":0.25, - "sliceSupportOffset":0.4, - "sliceSupportGap":1, - "sliceSupportSize":6, - "sliceSupportArea":1, - "sliceSupportExtra":0, - "sliceSupportAngle":50, - "sliceSupportNozzle":0, - "sliceSolidMinArea":1, - "sliceSolidLayers":3, - "sliceBottomLayers":3, - "sliceTopLayers":3, - "firstLayerRate":10, - "firstLayerPrintMult":1.15, - "firstLayerYOffset":0, - "firstLayerBrim":0, - "firstLayerBeltLead":3, - "outputTemp":210, - "outputBedTemp":60, - "outputFeedrate":50, - "outputFinishrate":50, - "outputSeekrate":80, - "outputShellMult":1.25, - "outputFillMult":1.25, - "outputSparseMult":1.25, - "outputRetractDist":4, - "outputRetractSpeed":30, - "outputRetractDwell":30, - "outputShortPoly":100, - "outputMinSpeed":10, - "outputCoastDist":0.1, - "outputLayerRetract":true, - "detectThinWalls":true, - "zHopDistance":0, - "antiBacklash":0, - "outputOriginCenter":false, - "sliceFillRate":0, - "sliceSupportEnable":false, - "firstSliceHeight":0.25, - "firstLayerFillRate":35, - "firstLayerLineMult":1, - "firstLayerNozzleTemp":0, - "firstLayerBedTemp":0, - "firstLayerBrimTrig":0, - "outputRaft":false, - "outputRaftSpacing":0.2, - "outputRetractWipe":0, - "outputBrimCount":2, - "outputBrimOffset":2, - "outputLoopLayers":null, - "outputInvertX":false, - "outputInvertY":false, - "arcTolerance":0, - "gcodePause":"", - "ranges":[], - "firstLayerFanSpeed":0, - "outputFanSpeed":255 - })) - .then(() => engine.setDevice({ - "noclone":false, - "mode":"FDM", - "internal":0, - "imageURL":"", - "imageScale":0.75, - "imageAnchor":0, - "bedHeight":2.5, - "bedWidth":220, - "bedDepth":220, - "bedRound":false, - "bedBelt":false, - "maxHeight":300, - "originCenter":false, - "extrudeAbs":true, - "spindleMax":0, - "gcodeFan":[ "M106 S{fan_speed}" ], - "gcodeTrack":[], - "gcodeLayer":[], - "gcodePre":[ - "M107 ; turn off filament cooling fan", - "G90 ; set absolute positioning mode", - "M82 ; set absolute positioning for extruder", - "M104 S{temp} T{tool} ; set extruder temperature", - "M140 S{bed_temp} T{tool} ; set bed temperature", - "G28 ; home axes", - "G92 X0 Y0 Z0 E0 ; reset all axes positions", - "G1 X0 Y0 Z0.25 F180 ; move XY to 0,0 and Z 0.25mm over bed", - "G92 E0 ; zero the extruded", - "M190 S{bed_temp} T{tool} ; wait for bed to reach target temp", - "M109 S{temp} T{tool} ; wait for extruder to reach target temp", - "G92 E0 ; zero the extruded", - "G1 F225 ; set feed speed" - ], - "gcodePost":[ - "M107 ; turn off filament cooling fan", - "M104 S0 T{tool} ; turn off right extruder", - "M140 S0 T{tool} ; turn off bed", - "G1 X0 Y300 F1200 ; end move", - "M84 ; disable stepper motors" - ], - "gcodeProc":"", - "gcodePause":[], - "gcodeDwell":[], - "gcodeSpindle":[], - "gcodeChange":[], - "gcodeFExt":"gcode", - "gcodeSpace":true, - "gcodeStrip":false, - "gcodeLaserOn":[], - "gcodeLaserOff":[], - "extruders":[ - { - "extFilament":1.75, - "extNozzle":0.4, - "extSelect":[ "T0" ], - "extDeselect":[], - "extOffsetX":0, - "extOffsetY":0 - } - ], - "new":false, - "deviceName":"Creality.Ender.3" - })) - .then(eng => eng.slice()) - .then(eng => eng.prepare()) - .then(eng => engine.export()) - .then(gcode => { - console.log({gcode}); - }) - .catch(error => { - console.log({error}); - }); -}); +run(); diff --git a/src/kiri/widget.js b/src/kiri/widget.js index 4c6b15d8..8e2465b5 100644 --- a/src/kiri/widget.js +++ b/src/kiri/widget.js @@ -954,6 +954,10 @@ console.log/** Copyright Stewart Allen -- All Rights Reserved */ }; PRO.setWireframe = function(set, color, opacity) { + if (!(KIRI.api && KIRI.api.conf)) { + // missing api features in engine mode + return; + } let mesh = this.mesh, widget = this; if (this.wire) {