add drag knife option in laser mode
This commit is contained in:
parent
a650382bd2
commit
f7ac50d2a6
11 changed files with 206 additions and 95 deletions
|
|
@ -221,9 +221,10 @@
|
|||
return ret;
|
||||
};
|
||||
|
||||
// use Slope.angleDiff() then re-test path mitering / rendering
|
||||
function slopeDiff(s1, s2) {
|
||||
const n1 = s1.angle;//(s1.angle + 360) % 360;
|
||||
const n2 = s2.angle;//(s2.angle + 360) % 360;
|
||||
const n1 = s1.angle;
|
||||
const n2 = s2.angle;
|
||||
let diff = n2 - n1;
|
||||
while (diff < -180) diff += 360;
|
||||
while (diff > 180) diff -= 360;
|
||||
|
|
@ -781,8 +782,6 @@
|
|||
*/
|
||||
PRO.isNested = function(parent) {
|
||||
if (parent.bounds.contains(this.bounds)) {
|
||||
//let int = POLY().rayIntersect(this.bounds.leftMost, nest_test_slope, [parent], false);
|
||||
//return int.length % 2 === 1 || this.isInside(parent, CONF.precision_nested_sq);
|
||||
return this.isInside(parent, CONF.precision_nested_sq);
|
||||
}
|
||||
return false;
|
||||
|
|
@ -1546,37 +1545,37 @@
|
|||
* rotate such that first and last points are the points
|
||||
* furthest apart and lowest when there is a tie breaker
|
||||
*/
|
||||
PRO.spread = function() {
|
||||
let poly = this,
|
||||
points = poly.points,
|
||||
plen = points.length,
|
||||
i, pp, np, p, mdelta, newmax, max, shift, maxd;
|
||||
|
||||
max = {d:0};
|
||||
maxd = 0;
|
||||
// find two most distance points
|
||||
for (i=0; i<plen; i++) {
|
||||
pp = points[i % plen];
|
||||
np = points[(i+1) % plen];
|
||||
p = ABS(pp.x - np.x) + ABS(pp.y - np.y);
|
||||
mdelta = ABS(p - max.d);
|
||||
newmax = p > maxd;
|
||||
maxd = MAX(maxd,p);
|
||||
// select lowest points (corner case = square)
|
||||
if (newmax || (mdelta < 0.001 && max.p1 && MIN(pp.z,np.z) < MIN(max.p1.z, max.p2.z))) {
|
||||
max = {p1:pp, p2:np, i:(i+1)%plen, d:p};
|
||||
}
|
||||
}
|
||||
|
||||
if (max.i > 0) {
|
||||
// shift array to start at "leftmost" Point
|
||||
shift = points.slice(max.i);
|
||||
shift.appendAll(points.slice(0,max.i));
|
||||
return newPolygon(shift);
|
||||
}
|
||||
|
||||
return poly;
|
||||
}
|
||||
// PRO.spread = function() {
|
||||
// let poly = this,
|
||||
// points = poly.points,
|
||||
// plen = points.length,
|
||||
// i, pp, np, p, mdelta, newmax, max, shift, maxd;
|
||||
//
|
||||
// max = {d:0};
|
||||
// maxd = 0;
|
||||
// // find two most distance points
|
||||
// for (i=0; i<plen; i++) {
|
||||
// pp = points[i % plen];
|
||||
// np = points[(i+1) % plen];
|
||||
// p = ABS(pp.x - np.x) + ABS(pp.y - np.y);
|
||||
// mdelta = ABS(p - max.d);
|
||||
// newmax = p > maxd;
|
||||
// maxd = MAX(maxd,p);
|
||||
// // select lowest points (corner case = square)
|
||||
// if (newmax || (mdelta < 0.001 && max.p1 && MIN(pp.z,np.z) < MIN(max.p1.z, max.p2.z))) {
|
||||
// max = {p1:pp, p2:np, i:(i+1)%plen, d:p};
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (max.i > 0) {
|
||||
// // shift array to start at "leftmost" Point
|
||||
// shift = points.slice(max.i);
|
||||
// shift.appendAll(points.slice(0,max.i));
|
||||
// return newPolygon(shift);
|
||||
// }
|
||||
//
|
||||
// return poly;
|
||||
// }
|
||||
|
||||
/** ******************************************************************
|
||||
* Connect to base and Helpers
|
||||
|
|
|
|||
|
|
@ -462,7 +462,7 @@
|
|||
* and return resulting gaps from offsets for thin wall detection in
|
||||
* in FDM mode and uncleared areas in CAM mode.
|
||||
*/
|
||||
function offset(polys, dist, options) {
|
||||
function offset(polys, dist, opts = {}) {
|
||||
// do not offset open lines
|
||||
polys = polys.filter(p => !p.open);
|
||||
|
||||
|
|
@ -475,7 +475,6 @@
|
|||
});
|
||||
|
||||
let orig = polys,
|
||||
opts = options || {},
|
||||
count = numOrDefault(opts.count, 1),
|
||||
depth = numOrDefault(opts.depth, 0),
|
||||
clean = opts.clean !== false,
|
||||
|
|
@ -483,7 +482,7 @@
|
|||
fill = numOrDefault(opts.fill, ClipperLib.PolyFillType.pftNonZero),
|
||||
join = numOrDefault(opts.join, ClipperLib.JoinType.jtMiter),
|
||||
type = numOrDefault(opts.type, ClipperLib.EndType.etClosedPolygon),
|
||||
coff = new ClipperLib.ClipperOffset(),
|
||||
coff = new ClipperLib.ClipperOffset(opts.miter, opts.arc),
|
||||
ctre = new ClipperLib.PolyTree(),
|
||||
// if dist is array with values, shift out next offset
|
||||
offs = Array.isArray(dist) ? (dist.length > 1 ? dist.shift() : dist[0]) : dist,
|
||||
|
|
|
|||
|
|
@ -95,6 +95,15 @@
|
|||
return this;
|
||||
};
|
||||
|
||||
PRO.angleDiff = function(s2,sign) {
|
||||
const n1 = this.angle;
|
||||
const n2 = s2.angle;
|
||||
let diff = n2 - n1;
|
||||
while (diff < -180) diff += 360;
|
||||
while (diff > 180) diff -= 360;
|
||||
return sign ? diff : Math.abs(diff);
|
||||
};
|
||||
|
||||
/** ******************************************************************
|
||||
* Connect to base and Helpers
|
||||
******************************************************************* */
|
||||
|
|
|
|||
|
|
@ -497,7 +497,6 @@
|
|||
laserSliceHeight: 1,
|
||||
laserSliceHeightMin: 0,
|
||||
laserSliceSingle: false,
|
||||
laserKnife: false,
|
||||
outputTileSpacing: 1,
|
||||
outputLaserPower: 100,
|
||||
outputLaserSpeed: 1000,
|
||||
|
|
@ -510,7 +509,8 @@
|
|||
outputInvertY: false,
|
||||
outputKnifeDepth: 1,
|
||||
outputKnifePasses: 1,
|
||||
outputTipOffset: 2
|
||||
outputKnifeTip: 2,
|
||||
knifeOn: false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1666,10 +1666,12 @@
|
|||
outputLaserMerged: UC.newBoolean(LANG.ou_mrgd_s, onBooleanClick, {title:LANG.ou_mrgd_l, modes:LASER}),
|
||||
outputLaserGroup: UC.newBoolean(LANG.ou_grpd_s, onBooleanClick, {title:LANG.ou_grpd_l, modes:LASER}),
|
||||
|
||||
knife: UC.newGroup(LANG.dk_menu, null, {modes:LASER, show:showLaserKnife }),
|
||||
outputKnifeDepth: UC.newInput(LANG.dk_dpth_s, {title:LANG.ou_exml_l, convert:UC.toFloat, bound:UC.bound(0.0,5.0), modes:LASER, show:showLaserKnife}),
|
||||
outputKnifePasses: UC.newInput(LANG.dk_pass_s, {title:LANG.dk_pass_l, convert:UC.toInt, bound:UC.bound(0,5), modes:LASER, show:showLaserKnife}),
|
||||
outputTipOffset: UC.newInput(LANG.dk_offs_s, {title:LANG.dk_offs_l, convert:UC.toFloat, bound:UC.bound(0.0,10.0), modes:LASER, show:showLaserKnife}),
|
||||
knife: UC.newGroup(LANG.dk_menu, null, {modes:LASER, marker:true}),
|
||||
outputKnifeDepth: UC.newInput(LANG.dk_dpth_s, {title:LANG.dk_dpth_l, convert:UC.toFloat, bound:UC.bound(0.0,5.0), modes:LASER}),
|
||||
outputKnifePasses: UC.newInput(LANG.dk_pass_s, {title:LANG.dk_pass_l, convert:UC.toInt, bound:UC.bound(0,5), modes:LASER}),
|
||||
outputKnifeTip: UC.newInput(LANG.dk_offs_s, {title:LANG.dk_offs_l, convert:UC.toFloat, bound:UC.bound(0.0,10.0), modes:LASER}),
|
||||
knifeSep: UC.newBlank({class:"pop-sep", modes:LASER}),
|
||||
knifeOn: UC.newBoolean(LANG.enable, onBooleanClick, {title:LANG.ou_drkn_l, modes:LASER}),
|
||||
|
||||
output: UC.newGroup(LANG.ou_menu, null, {modes:GCODE}),
|
||||
outputLaserPower: UC.newInput(LANG.ou_powr_s, {title:LANG.ou_powr_l, convert:UC.toInt, bound:UC.bound(1,100), modes:LASER}),
|
||||
|
|
@ -1696,7 +1698,6 @@
|
|||
outputOriginBounds: UC.newBoolean(LANG.or_bnds_s, onBooleanClick, {title:LANG.or_bnds_l, modes:LASER}),
|
||||
outputOriginCenter: UC.newBoolean(LANG.or_cntr_s, onBooleanClick, {title:LANG.or_cntr_l, modes:CAM_LASER}),
|
||||
camOriginTop: UC.newBoolean(LANG.or_topp_s, onBooleanClick, {title:LANG.or_topp_l, modes:CAM}),
|
||||
laserKnife: UC.newBoolean(LANG.ou_drkn_s, onBooleanClick, {title:LANG.ou_drkn_l, modes:[]}),
|
||||
|
||||
advanced: UC.newGroup(LANG.ad_menu, null, {modes:FDM, expert:true}),
|
||||
outputRetractDist: UC.newInput(LANG.ad_rdst_s, {title:LANG.ad_rdst_l, convert:UC.toFloat, modes:FDM, expert:true}),
|
||||
|
|
@ -1767,10 +1768,6 @@
|
|||
layers: UC.setGroup($("layers")),
|
||||
});
|
||||
|
||||
function showLaserKnife() {
|
||||
return UI.laserKnife.checked;
|
||||
}
|
||||
|
||||
function spindleShow() {
|
||||
return settings().device.spindleMax > 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -321,11 +321,10 @@
|
|||
* @param {Function} [onfirst] optional fn to call on first point
|
||||
* @return {Point} last output point
|
||||
*/
|
||||
PRO.polyPrintPath = function(poly, startPoint, output, opt) {
|
||||
PRO.polyPrintPath = function(poly, startPoint, output, options = {}) {
|
||||
poly.setClockwise();
|
||||
|
||||
let options = opt || {},
|
||||
process = this.settings.process,
|
||||
let process = this.settings.process,
|
||||
shortDist = process.outputShortDistance,
|
||||
shellMult = pref(options.extrude, process.outputShellMult),
|
||||
printSpeed = options.rate || process.outputFeedrate,
|
||||
|
|
|
|||
|
|
@ -220,6 +220,7 @@ KIRI.worker = {
|
|||
out.point = BASE.newPoint(x,y,z || 0);
|
||||
});
|
||||
});
|
||||
const print = current.print = KIRI.newPrint(null, Object.values(cache));
|
||||
const layers = KIRI.driver.FDM.prepareRender(parsed, progress => {
|
||||
send.data({ progress });
|
||||
}, { thin: true });
|
||||
|
|
|
|||
|
|
@ -550,10 +550,11 @@
|
|||
spindle = Math.min(spindleMax, process.camOutlineSpindle);
|
||||
let flatLevels = depthData.outline.map(level => {
|
||||
return POLY.flatten(level.clone(true), [], true).filter(p => !(p.depth = 0));
|
||||
});
|
||||
// flatLevels.xout('flat');
|
||||
}).filter(l => l.length > 0);
|
||||
flatLevels.xout('flat');
|
||||
// start with the smallest polygon on the top
|
||||
printPoint = flatLevels[0]
|
||||
// .filter(l => l.length > 0)[0]
|
||||
.sort((a,b) => { return a.area() - b.area() })[0]
|
||||
.average();
|
||||
printPoint = depthOutlinePath(printPoint, 0, flatLevels, toolDiam, polyEmit, false);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
FDM = KIRI.driver.FDM,
|
||||
CAM = KIRI.driver.CAM,
|
||||
LASER = KIRI.driver.LASER = {
|
||||
init,
|
||||
slice,
|
||||
prepare,
|
||||
export: exportLaser,
|
||||
|
|
@ -24,6 +25,13 @@
|
|||
SLICER = KIRI.slicer,
|
||||
newPoint = BASE.newPoint;
|
||||
|
||||
function init(kiri, api) {
|
||||
api.event.on("settings.saved", (settings) => {
|
||||
let UI = kiri.api.ui;
|
||||
UI.knife.marker.style.display = UI.knifeOn.checked ? '' : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* DRIVER SLICE CONTRACT
|
||||
*
|
||||
|
|
@ -34,6 +42,7 @@
|
|||
*/
|
||||
function slice(settings, widget, onupdate, ondone) {
|
||||
let proc = settings.process;
|
||||
let offset = proc.laserOffset;
|
||||
|
||||
if (proc.laserSliceHeight < 0) {
|
||||
return ondone("invalid slice height");
|
||||
|
|
@ -46,8 +55,11 @@
|
|||
}, function(slices) {
|
||||
widget.slices = slices;
|
||||
slices.forEach(function(slice, index) {
|
||||
FDM.share.doShells(slice, 1, -proc.laserOffset);
|
||||
slice.output().setLayer("slice").addPolys(slice.topPolys());
|
||||
let tops = slice.tops.map(t => t.poly);
|
||||
let offsets = slice.offset = offset ?
|
||||
POLY.offset(tops, offset, {z: slice.z, miter: 2 / offset}) : tops;
|
||||
slice.output().setLayer("layer", { line: 0x888800 }).addPolys(tops);
|
||||
slice.output().setLayer("cut").addPolys(offsets);
|
||||
onupdate(0.80 + (index/slices.length) * 0.20);
|
||||
});
|
||||
ondone();
|
||||
|
|
@ -56,7 +68,7 @@
|
|||
});
|
||||
};
|
||||
|
||||
function sliceEmitObjects(print, slice, groups) {
|
||||
function sliceEmitObjects(print, slice, groups, simple) {
|
||||
let start = newPoint(0,0,0);
|
||||
let process = print.settings.process;
|
||||
let grouped = process.outputLaserGroup;
|
||||
|
|
@ -74,14 +86,19 @@
|
|||
laserOut(pi, group);
|
||||
});
|
||||
} else {
|
||||
print.polyPrintPath(poly, start, group,
|
||||
zcolor ? {extrude: slice.z, rate: slice.z} : {extrude: 1}
|
||||
);
|
||||
let pathOpt = zcolor ? {extrude: slice.z, rate: slice.z} : {extrude: 1};
|
||||
if (simple) pathOpt.simple = true;
|
||||
if (poly.open) pathOpt.open = true;
|
||||
print.polyPrintPath(poly, start, group, pathOpt);
|
||||
}
|
||||
}
|
||||
|
||||
laserOut(slice.topPolyInners(), group);
|
||||
laserOut(slice.topShells(), group);
|
||||
let offset = slice.offset;
|
||||
let inner = offset.map(poly => poly.inner || []).flat();
|
||||
|
||||
laserOut(offset, group);
|
||||
laserOut(inner, group);
|
||||
|
||||
if (!grouped) {
|
||||
groups.push(group);
|
||||
group = [];
|
||||
|
|
@ -103,10 +120,76 @@
|
|||
let device = settings.device,
|
||||
process = settings.process,
|
||||
print = self.worker.print = KIRI.newPrint(settings, widgets),
|
||||
knifeOn = process.knifeOn,
|
||||
knifeDepth = process.outputKnifeDepth,
|
||||
knifePasses = process.outputKnifePasses,
|
||||
knifeTipOff = process.outputKnifeTip,
|
||||
output = print.output = [],
|
||||
totalSlices = 0,
|
||||
slices = 0;
|
||||
|
||||
function arc(center, s1, s2, out) {
|
||||
let a1 = s1.angle;
|
||||
let a2 = s2.angle;
|
||||
let diff = s1.angleDiff(s2,true);
|
||||
let step = 5;
|
||||
let ticks = Math.abs(Math.floor(diff / step));
|
||||
let dir = Math.sign(diff);
|
||||
let off = (diff % step) / 2;
|
||||
if (off == 0) {
|
||||
ticks++;
|
||||
} else {
|
||||
out.push( center.projectOnSlope(s1, knifeTipOff) );
|
||||
}
|
||||
while (ticks-- > 0) {
|
||||
out.push( center.projectOnSlope(BASE.newSlopeFromAngle(a1 + off), knifeTipOff) );
|
||||
a1 += step * dir;
|
||||
}
|
||||
out.push( center.projectOnSlope(s2, knifeTipOff) );
|
||||
}
|
||||
|
||||
// start to the "left" of the first point
|
||||
function addKnifeRadii(poly) {
|
||||
poly.setClockwise();
|
||||
let oldpts = poly.points.slice();
|
||||
// find leftpoint and make that the first point
|
||||
let start = oldpts[0];
|
||||
let startI = 0;
|
||||
for (let i=1; i<oldpts.length; i++) {
|
||||
let pt = oldpts[i];
|
||||
if (pt.x < start.x || pt.y > start.y) {
|
||||
start = pt;
|
||||
startI = i;
|
||||
}
|
||||
}
|
||||
if (startI > 0) {
|
||||
oldpts = oldpts.slice(startI,oldpts.length).appendAll(oldpts.slice(0,startI));
|
||||
}
|
||||
|
||||
let lastpt = oldpts[0].clone().move({x:-knifeTipOff,y:0,z:0});
|
||||
let lastsl = lastpt.slopeTo(oldpts[0]).toUnit();
|
||||
let newpts = [ lastpt, lastpt = oldpts[0] ];
|
||||
let tmp;
|
||||
for (let i=1; i<oldpts.length + 1; i++) {
|
||||
let nextpt = oldpts[i % oldpts.length];
|
||||
let nextsl = lastpt.slopeTo(nextpt).toUnit();
|
||||
if (lastsl.angleDiff(nextsl) >= 10 && lastpt.distTo2D(nextpt) >= knifeTipOff) {
|
||||
arc(lastpt, lastsl, nextsl, newpts);
|
||||
// let tmp;
|
||||
// newpts.push( tmp = lastpt.projectOnSlope(lastsl, knifeTipOff) );
|
||||
// newpts.push( lastpt.projectOnSlope(nextsl, knifeTipOff) );
|
||||
}
|
||||
newpts.push(nextpt);
|
||||
lastsl = nextsl;
|
||||
lastpt = nextpt;
|
||||
}
|
||||
newpts.push( tmp = lastpt.projectOnSlope(lastsl, knifeTipOff) );
|
||||
newpts.push( tmp.clone().move({x:knifeTipOff, y:0, z: 0}) );
|
||||
poly.open = true;
|
||||
poly.points = newpts;
|
||||
poly.length = newpts.length;
|
||||
}
|
||||
|
||||
// find max layers (for updates)
|
||||
widgets.forEach(function(widget) {
|
||||
totalSlices += widget.slices.length;
|
||||
|
|
@ -119,7 +202,7 @@
|
|||
let merged = [];
|
||||
widget.slices.forEach(function(slice) {
|
||||
let polys = [];
|
||||
slice.topPolys().clone(true).forEach(p => p.flattenTo(polys));
|
||||
slice.offsets.clone(true).forEach(p => p.flattenTo(polys));
|
||||
polys.forEach(p => {
|
||||
let match = false;
|
||||
for (let i=0; i<merged.length; i++) {
|
||||
|
|
@ -147,8 +230,18 @@
|
|||
});
|
||||
output.push(gather);
|
||||
} else {
|
||||
if (knifeOn) {
|
||||
widget.slices.forEach(slice => {
|
||||
slice.offset.forEach(poly => {
|
||||
addKnifeRadii(poly);
|
||||
if (poly.inner) poly.inner.forEach(ip => {
|
||||
addKnifeRadii(ip);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
widget.slices.forEach(function(slice) {
|
||||
sliceEmitObjects(print, slice, output);
|
||||
sliceEmitObjects(print, slice, output, knifeOn);
|
||||
update((slices++ / totalSlices) * 0.5, "prepare");
|
||||
});
|
||||
}
|
||||
|
|
@ -205,13 +298,9 @@
|
|||
});
|
||||
}
|
||||
|
||||
// if (process.laserKnife) {
|
||||
// console.log({laser_it: output});
|
||||
// }
|
||||
|
||||
return print.render = FDM.prepareRender(output, (progress, layer) => {
|
||||
update(0.5 + progress * 0.5, "render", layer);
|
||||
}, { thin: true, z: 0, action: "cut" });
|
||||
}, { thin: true, z: 0, action: "cut", moves: process.knifeOn });
|
||||
};
|
||||
|
||||
function exportLaser(print, online, ondone) {
|
||||
|
|
@ -310,10 +399,14 @@
|
|||
function exportGCode(settings, data) {
|
||||
let lines = [], dx = 0, dy = 0, z = 0, feedrate;
|
||||
let dev = settings.device;
|
||||
let proc = settings.process;
|
||||
let space = dev.gcodeSpace ? ' ' : '';
|
||||
let power = 255;
|
||||
let laser_on = dev.gcodeLaserOn || [];
|
||||
let laser_off = dev.gcodeLaserOff || [];
|
||||
let knifeOn = proc.knifeOn;
|
||||
let knifeDepth = proc.outputKnifeDepth;
|
||||
let passes = knifeOn ? proc.outputKnifePasses : 1;
|
||||
|
||||
exportElements(
|
||||
settings,
|
||||
|
|
@ -332,25 +425,41 @@
|
|||
});
|
||||
},
|
||||
function(poly, color, thick) {
|
||||
poly.forEach(function(point, index) {
|
||||
if (index === 0) {
|
||||
lines.push(`G0${space}${point}`);
|
||||
} else if (index === 1) {
|
||||
laser_on.forEach(line => {
|
||||
line = line.replace('{power}', power);
|
||||
line = line.replace('{color}', color);
|
||||
line = line.replace('{thick}', thick);
|
||||
line = line.replace('{z}', z);
|
||||
lines.push(line);
|
||||
});
|
||||
lines.push(`G1${space}${point}${feedrate}`);
|
||||
} else {
|
||||
lines.push(`G1${space}${point}`);
|
||||
}
|
||||
});
|
||||
laser_off.forEach(line => {
|
||||
lines.push(line);
|
||||
});
|
||||
if (knifeOn) {
|
||||
lines.push(`; start new poly id=${poly.id} len=${poly.length}`);
|
||||
}
|
||||
for (let i=0; i<passes; i++) {
|
||||
poly.forEach(function(point, index) {
|
||||
if (index === 0) {
|
||||
if (knifeOn) {
|
||||
// lift
|
||||
lines.appendAll(['; drag-knife lift', `G0${space}Z5`]);
|
||||
}
|
||||
lines.push(`G0${space}${point}`);
|
||||
if (knifeOn) {
|
||||
// drop
|
||||
lines.appendAll(['; drag-knife down', `G0${space}Z${-i*knifeDepth}`]);
|
||||
}
|
||||
} else if (index === 1) {
|
||||
laser_on.forEach(line => {
|
||||
line = line.replace('{power}', power);
|
||||
line = line.replace('{color}', color);
|
||||
line = line.replace('{thick}', thick);
|
||||
line = line.replace('{z}', z);
|
||||
lines.push(line);
|
||||
});
|
||||
lines.push(`G1${space}${point}${feedrate}`);
|
||||
} else {
|
||||
lines.push(`G1${space}${point}`);
|
||||
}
|
||||
});
|
||||
laser_off.forEach(line => {
|
||||
lines.push(line);
|
||||
});
|
||||
}
|
||||
if (knifeOn) {
|
||||
lines.appendAll([`G0${space}Z5`]);
|
||||
}
|
||||
},
|
||||
function() {
|
||||
(dev.gcodePost || []).forEach(line => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue