grid-apps-cmms/src/mode/fdm/export.js

723 lines
29 KiB
JavaScript
Raw Normal View History

2020-11-05 18:29:04 -05:00
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
"use strict";
(function() {
let KIRI = self.kiri,
BASE = self.base,
UTIL = BASE.util,
FDM = KIRI.driver.FDM,
debug = false;
2020-11-05 18:29:04 -05:00
/**
* @returns {Array} gcode lines
*/
2021-06-18 15:03:00 -04:00
FDM.export = function(print, online, ondone, ondebug) {
2020-11-05 18:29:04 -05:00
let layers = print.output,
settings = FDM.fixExtruders(print.settings),
2021-02-11 17:34:42 -05:00
getRangeParameters = FDM.getRangeParameters,
2020-11-05 18:29:04 -05:00
device = settings.device,
extruders = device.extruders,
gcodeFan = device.gcodeFan,
gcodeLayer = device.gcodeLayer,
gcodeTrack = device.gcodeTrack,
gcodeExt = device.gcodeExt,
gcodeInt = device.gcodeInt,
2020-11-05 18:29:04 -05:00
tool = 0,
fwRetract = device.fwRetract,
isDanger = settings.controller.danger,
2021-01-09 19:10:39 -05:00
isBelt = device.bedBelt,
2021-01-07 18:41:53 -05:00
bedType = isBelt ? "belt" : "fixed",
2020-11-05 18:29:04 -05:00
extruder = extruders[tool],
offset_x = extruder.extOffsetX,
offset_y = extruder.extOffsetY,
extrudeAbs = device.extrudeAbs || false,
extrudeSet = false,
2020-11-05 18:29:04 -05:00
time = 0,
layer = 0,
layerno = 0,
2020-11-05 18:29:04 -05:00
pause = [],
pauseCmd = device.gcodePause,
output = [],
2021-02-04 21:35:42 -05:00
outputLength = 0, // absolute extruder position
2020-11-05 18:29:04 -05:00
lastProgress = 0,
decimals = BASE.config.gcode_decimals || 4,
progress = 0,
distance = 0,
emitted = 0,
retracted = 0,
pos = {x:0, y:0, z:0, f:0},
lout = null,
2020-11-05 18:29:04 -05:00
last = null,
zpos = 0,
bmax = 0,
blast = 0,
blastz = 0,
2021-02-11 17:34:42 -05:00
process = settings.process,
belt_add_y = (process.firstLayerYOffset || 0) - (print.belty || 0),
loops = process.outputLoops || 0,
2021-02-11 17:34:42 -05:00
zhop = process.zHopDistance || 0, // range
2021-06-14 12:09:59 -04:00
lineWidth = process.sliceLineWidth || 0,
2020-11-05 18:29:04 -05:00
seekMMM = process.outputSeekrate * 60,
retDist = process.outputRetractDist || 0, // range
2021-02-11 17:34:42 -05:00
retSpeed = process.outputRetractSpeed * 60, // range
retDwell = process.outputRetractDwell || 0, // range
2020-11-05 18:29:04 -05:00
timeDwell = retDwell / 1000,
peelGuard = process.outputPeelGuard || 0,
2021-02-07 19:25:30 -05:00
arcDist = isBelt || !isDanger ? 0 : (process.arcTolerance || 0),
arcMin = 1,
arcRes = 16,
arcDev = 0.5,
arcMax = 200,
arcSegMax = 1,
2021-01-16 20:39:55 -05:00
originCenter = process.outputOriginCenter,
offset = originCenter ? null : {
2020-11-05 18:29:04 -05:00
x: device.bedWidth/2,
2021-01-08 14:42:01 -05:00
y: isBelt ? 0 : device.bedDepth/2
2020-11-05 18:29:04 -05:00
},
nozzleTemp = process.firstLayerNozzleTemp || process.outputTemp,
bedTemp = process.firstLayerBedTemp || process.outputBedTemp,
fanSpeed = undefined,
lastType = undefined,
lastNozzleTemp = nozzleTemp,
lastBedTemp = bedTemp,
lastFanSpeed = fanSpeed,
2020-11-05 18:29:04 -05:00
subst = {
travel_speed: seekMMM,
retract_speed: retSpeed,
retract_distance: retDist,
temp: nozzleTemp,
temp_bed: bedTemp,
bed_temp: bedTemp,
fan_speed: fanSpeed,
speed: fanSpeed, // legacy
2020-11-05 18:29:04 -05:00
top: offset ? device.bedDepth : device.bedDepth/2,
left: offset ? 0 : -device.bedWidth/2,
right: offset ? device.bedWidth : device.bedWidth/2,
bottom: offset ? 0 : -device.bedDepth/2,
z_max: device.maxHeight,
layers: layers.length,
progress: 0,
2020-11-05 18:29:04 -05:00
nozzle: 0,
tool: 0
},
pidx, path, out, speedMMM, emitMM, emitPerMM, lastp, laste, dist,
append,
lines = 0,
2021-01-07 18:41:53 -05:00
bytes = 0,
bcos = Math.cos(Math.PI/4),
icos = 1 / bcos,
2021-02-04 21:35:42 -05:00
inLoop,
arcQ = [],
minz = { x: Infinity, y: Infinity, z: Infinity };
// smallish band-aid. refactor above to remove redundancy
function updateParams(layer) {
let process = getRangeParameters(settings, layer);
zhop = process.zHopDistance || 0; // range
retDist = process.outputRetractDist || 0; // range
retSpeed = process.outputRetractSpeed * 60; // range
retDwell = process.outputRetractDwell || 0; // range
timeDwell = retDwell / 1000;
nozzleTemp = layer === 0 ?
process.firstLayerNozzleTemp || process.outputTemp :
process.outputTemp || process.firstLayerNozzleTemp;
bedTemp = layer === 0 ?
process.firstLayerBedTemp || process.outputBedTemp :
process.outputBedTemp || process.firstLayerBedTemp;
fanSpeed = layer === 0 ?
process.firstLayerFanSpeed || 0 :
process.outputFanSpeed || 0;
Object.assign(subst, {
temp_bed: bedTemp,
bed_temp: bedTemp,
fan_speed: fanSpeed,
speed: fanSpeed, // legacy
retract_speed: retSpeed,
retract_distance: retDist,
temp: process.outputTemp, // range
temp_bed: process.outputBedTemp, // range
bed_temp: process.outputBedTemp, // range
});
}
// collect loops from ranges and synth range array
let rloops = [];
if (loops > 0) {
rloops.push({
start: layers[0].slice.index,
end: layers.last().slice.index,
iter: loops - 1
});
}
2021-06-13 05:52:52 -04:00
if (process.ranges)
for (let range of process.ranges) {
if (range.fields.outputLoops) {
rloops.push({
start: range.lo,
end: range.hi,
iter: range.fields.outputLoops - 1
});
}
}
loops = isBelt && rloops.length ? rloops : undefined;
2020-11-05 18:29:04 -05:00
(process.gcodePauseLayers || "").split(",").forEach(function(lv) {
let v = parseInt(lv);
if (v >= 0) pause.push(v);
});
2020-11-08 19:38:02 -05:00
append = function(line) {
if (line) {
2020-11-05 18:29:04 -05:00
lines++;
bytes += line.length;
2020-11-08 19:38:02 -05:00
output.append(line);
2020-11-05 18:29:04 -05:00
}
2020-11-08 19:38:02 -05:00
if (!line || output.length > 1000) {
online(output.join("\n"));
output = [];
}
};
2020-11-05 18:29:04 -05:00
function appendSubPad(line, pad) {
appendSub(line, true);
}
function appendSub(line, pad) {
append(print.constReplace(line, subst, 0, pad));
2020-11-05 18:29:04 -05:00
}
function appendAll(arr) {
if (!arr) return;
if (!Array.isArray(arr)) arr = [ arr ];
arr.forEach(function(line) { append(line) });
}
function appendAllSub(arr, pad) {
if (!arr || arr.length === 0) return;
2020-11-05 18:29:04 -05:00
if (!Array.isArray(arr)) arr = [ arr ];
arr.forEach(function(line) { appendSub(line, pad) });
2020-11-05 18:29:04 -05:00
}
append(`; Generated by Kiri:Moto ${KIRI.version}`);
append(`; ${new Date().toString()}`);
appendSub("; Bed left:{left} right:{right} top:{top} bottom:{bottom}");
append(`; Bed type: ${bedType}`);
2020-11-05 18:29:04 -05:00
append(`; Target: ${settings.filter[settings.mode]}`);
append("; --- process ---");
for (let pk in process) {
append("; " + pk + " = " + process[pk]);
}
append("; --- startup ---");
let t0 = false;
let t1 = false;
for (let i=0; i<device.gcodePre.length; i++) {
let line = device.gcodePre[i];
2021-03-11 10:36:51 -05:00
if (line.indexOf('T0') === 0) t0 = true; else
if (line.indexOf('T1') === 0) t1 = true; else
if (line.indexOf('M82') === 0) {
extrudeAbs = true;
extrudeSet = true;
} else
if (line.indexOf('M83') === 0) {
extrudeAbs = false;
extrudeSet = true;
} else
2021-03-11 10:36:51 -05:00
if (line.indexOf('G90') === 0 && !extrudeSet) extrudeAbs = true; else
if (line.indexOf('G91') === 0 && !extrudeSet) extrudeAbs = false; else
2020-11-05 18:29:04 -05:00
if (line.indexOf('G92') === 0) {
line.split(";")[0].split(' ').forEach(function (tok) {
let val = parseFloat(tok.substring(1) || 0) || 0;
switch (tok[0]) {
case 'X': pos.x = val; break;
case 'Y': pos.y = val; break;
case 'Z': pos.z = val; break;
case 'E': outputLength = val; break;
}
});
}
if (extrudeAbs && line.indexOf('E') > 0) {
line.split(";")[0].split(' ').forEach(function (tok) {
// use max E position from gcode-preamble
if (tok[0] == 'E') {
outputLength = Math.max(outputLength, parseFloat(tok.substring(1)) || 0);
}
});
}
if (line.indexOf("{tool}") > 0 && extruders.length > 1) {
for (let i=0; i<extruders.length; i++) {
subst.tool = i;
appendSubPad(line);
}
subst.tool = 0;
} else {
appendSubPad(line);
}
2020-11-05 18:29:04 -05:00
}
function dwell(ms) {
append(`G4 P${ms}`);
time += timeDwell;
}
function retract(zhop) {
2021-01-24 18:35:19 -05:00
if (retracted) {
// console.log({double_retract: zhop});
return;
}
2020-11-05 18:29:04 -05:00
retracted = retDist;
if (fwRetract) {
append('G10');
} else {
moveTo({e:-retracted}, retSpeed, `e-retract ${retDist}`);
}
2020-11-05 18:29:04 -05:00
if (zhop) moveTo({z:zpos + zhop}, seekMMM, "z-hop start");
time += (retDist / retSpeed) * 60 * 2; // retraction time
}
2021-01-07 18:41:53 -05:00
let taxis = new THREE.Vector3( 1, 0, 0 );
let tcent = new THREE.Vector2( 0, 0 );
let angle = -Math.PI / 4;
2020-11-05 18:29:04 -05:00
function moveTo(newpos, rate, comment) {
let o = [!rate && !newpos.e ? 'G0' : 'G1'];
let emit = { x: false, y: false, z: false };
if (typeof newpos.x === 'number' && newpos.x !== pos.x) {
pos.x = newpos.x;
2021-01-07 18:41:53 -05:00
emit.x = true;
2020-11-05 18:29:04 -05:00
}
if (typeof newpos.y === 'number' && newpos.y !== pos.y) {
pos.y = newpos.y;
2021-01-07 18:41:53 -05:00
emit.y = true;
if (isBelt) emit.z = true;
2020-11-05 18:29:04 -05:00
}
if (typeof newpos.z === 'number' && newpos.z !== pos.z) {
pos.z = newpos.z;
2021-01-07 18:41:53 -05:00
emit.z = true;
if (isBelt) emit.y = true;
2021-01-07 18:41:53 -05:00
}
let epos = isBelt ? { x: pos.x, y: pos.y, z: pos.z } : pos;
if (isBelt) {
let zheight = path ? path.height || 0 : 0;
2021-01-16 20:39:55 -05:00
epos.x = originCenter ? -pos.x : device.bedWidth - pos.x;
epos.z = blastz = pos.z * icos;
epos.y = -pos.y + epos.z * bcos + belt_add_y;
lout = epos;
2020-11-05 18:29:04 -05:00
}
2021-01-07 18:41:53 -05:00
if (emit.x) o.append(" X").append(epos.x.toFixed(decimals));
if (emit.y) o.append(" Y").append(epos.y.toFixed(decimals));
if (emit.z) o.append(" Z").append(epos.z.toFixed(decimals));
if (debug) {
if (emit.x) minz.x = Math.min(minz.x, epos.x);
if (emit.y) minz.y = Math.min(minz.y, epos.y);
if (emit.z) minz.z = Math.min(minz.z, epos.z);
}
2020-11-05 18:29:04 -05:00
if (typeof newpos.e === 'number') {
outputLength += newpos.e;
if (extrudeAbs) {
// for cumulative (absolute) extruder positions
o.append(" E").append(outputLength.toFixed(decimals));
} else {
o.append(" E").append(newpos.e.toFixed(decimals));
}
}
if (rate && rate != pos.f) {
o.append(" F").append(Math.round(rate));
pos.f = rate
}
if (comment) {
o.append(` ; ${comment}`);
}
if (o.length === 1) {
// console.trace({no_move: o, out, newpos, pos, lastp, emit});
return;
}
2020-11-05 18:29:04 -05:00
let line = o.join('');
if (last == line) {
// console.log({dup:line});
return;
}
last = line;
append(line);
}
// calc total distance traveled by head as proxy for progress
let allout = [], totaldistance = 0;
layers.forEach(function(outs) {
allout.appendAll(outs);
});
allout.forEachPair(function (o1, o2) {
totaldistance += o1.point.distTo2D(o2.point);
}, 1);
// retract before first move
retract();
while (layer < layers.length) {
path = layers[layer];
layerno = path.slice.index;
// range overrides
if (path.layer >= 0) {
updateParams(path.layer);
}
2021-02-11 17:34:42 -05:00
2020-11-05 18:29:04 -05:00
emitPerMM = print.extrudePerMM(
2021-06-14 12:09:59 -04:00
lineWidth || extruder.extNozzle,
2020-11-05 18:29:04 -05:00
extruder.extFilament,
path.layer === 0 ?
(process.firstSliceHeight || process.sliceHeight) : path.height);
2021-03-02 18:36:08 -05:00
zpos = path.z || zpos;
bmax = Math.max(bmax, pos.z * icos);
subst.z = subst.Z = zpos.round(3);
subst.e = subst.E = outputLength;
2020-11-05 18:29:04 -05:00
subst.layer = layer;
subst.height = path.height.toFixed(3);
if (isBelt) {
pos.z = zpos;
if (peelGuard && bmax > peelGuard && blast < peelGuard) {
peelGuard += 50;
append(`G0 Z${(blast + 55).round(decimals)} F200 ; peel guard`);
append(`G0 Z${blastz.round(decimals)} F200 ; unpeel`);
}
blast = bmax;
}
2020-11-05 18:29:04 -05:00
if (pauseCmd && pause.indexOf(layer) >= 0) {
appendAllSub(pauseCmd)
}
let endloop = false;
if (loops) {
if (inLoop) {
if (layerno === inLoop.end) {
endloop = true;
// append(`M808`);
// inLoop = undefined;
}
} else {
for (let loop of loops) {
if (layerno === loop.start) {
append(`M808 L${loop.iter}`);
if (extrudeAbs) {
append(`G92 Z${lout.z.round(decimals)} E${outputLength.round(decimals)}`);
} else {
append(`G92 Z${lout.z.round(decimals)}`);
}
inLoop = loop;
break;
}
}
}
}
2020-11-05 18:29:04 -05:00
if (gcodeLayer && gcodeLayer.length) {
appendAllSub(gcodeLayer);
} else {
append(`;; --- layer ${layer} (${subst.height} @ ${subst.z.round(3)}) ---`);
2020-11-05 18:29:04 -05:00
}
// layer temp and fan overrides at layer changes
if (fanSpeed !== lastFanSpeed) {
2020-11-05 18:29:04 -05:00
appendAllSub(gcodeFan);
lastFanSpeed = fanSpeed;
2020-11-05 18:29:04 -05:00
}
if (bedTemp !== lastBedTemp) {
append(`M140 S${bedTemp} T0`);
lastBedTemp = bedTemp;
}
if (nozzleTemp !== lastNozzleTemp) {
if (t0) append(`M104 S${nozzleTemp} T0`);
if (t1) append(`M104 S${nozzleTemp} T1`);
2021-02-22 18:45:58 -05:00
if (!(t0 || t1)) append(`M104 S${nozzleTemp} T${tool}`);
lastNozzleTemp = nozzleTemp;
2020-11-05 18:29:04 -05:00
}
// move Z to layer height
2021-01-08 14:42:01 -05:00
if (layer > 0 || !isBelt) {
moveTo({z:zpos}, seekMMM);
}
2020-11-05 18:29:04 -05:00
// iterate through layer outputs
for (pidx=0; pidx<path.length; pidx++) {
out = path[pidx];
2021-02-11 17:34:42 -05:00
speedMMM = (out.speed || process.outputFeedrate) * 60; // range
2020-11-05 18:29:04 -05:00
// emit gcode macro for changed print region
if (out.type !== last.type) {
switch (out.type) {
case 'ext':
appendAllSub(gcodeExt);
break;
case 'int':
appendAllSub(gcodeInt);
break;
}
lastType = out.type;
}
// look for extruder change, run scripts, recalc emit factor
2021-05-26 14:51:22 -04:00
if (out.tool !== undefined && out.tool != tool) {
appendAllSub(extruder.extDeselect);
2020-11-05 18:29:04 -05:00
tool = out.tool;
subst.nozzle = subst.tool = tool;
extruder = extruders[tool];
offset_x = extruder.extOffsetX;
offset_y = extruder.extOffsetY;
emitPerMM = print.extrudePerMM(
2021-06-14 12:09:59 -04:00
lineWidth || extruder.extNozzle,
2020-11-05 18:29:04 -05:00
extruder.extFilament,
path.layer === 0 ?
(process.firstSliceHeight || process.sliceHeight) : path.height);
appendAllSub(extruder.extSelect);
}
// if no point in output, it's a dwell command
if (!out.point) {
dwell(out.speed);
continue;
}
let x = out.point.x + offset_x,
y = out.point.y + offset_y,
z = out.point.z;
2021-01-08 14:42:01 -05:00
// adjust for inversions and origin offsets
2020-11-05 18:29:04 -05:00
if (process.outputInvertX) x = -x;
if (process.outputInvertY) y = -y;
if (offset) {
x += offset.x;
y += offset.y;
}
dist = lastp ? lastp.distTo2D(out.point) : 0;
// re-engage post-retraction before new extrusion
if (out.emit && retracted) {
2021-02-04 21:35:42 -05:00
drainQ();
2021-01-24 18:35:19 -05:00
// console.log({engage:zhop});
2020-11-05 18:29:04 -05:00
// when enabled, resume previous Z
if (zhop && pos.z != zpos) moveTo({z:zpos}, seekMMM, "z-hop end");
// re-engage retracted filament
if (fwRetract) {
append('G11');
} else {
moveTo({e:retracted}, retSpeed, `e-engage ${retracted}`);
}
2020-11-05 18:29:04 -05:00
retracted = 0;
// optional dwell after re-engaging filament to allow pressure to build
if (retDwell) dwell(retDwell);
time += (retDist / retSpeed) * 60 * 2; // retraction time
}
if (lastp && out.emit) {
2021-02-04 21:35:42 -05:00
if (arcDist) {
let rec = {e:out.emit, x, y, z, dist, emitPerMM, speedMMM};
arcQ.push(rec);
2021-06-18 15:03:00 -04:00
// ondebug({arcQ});
let deem = false; // do arcQ[0] and rec have differing emit values?
let depm = false; // do arcQ[0] and rec have differing emit speeds?
let desp = false; // do arcQ[0] and rec have differing move speeds?
let arcSeg = 0; // distance from this point to the last
2021-02-04 21:35:42 -05:00
if (arcQ.length > 1) {
let el = arcQ.length;
2021-02-04 21:35:42 -05:00
deem = arcQ[0].e !== rec.e;
depm = arcQ[0].emitPerMM !== rec.emitPerMM;
desp = arcQ[0].speedMMM !== rec.speedMMM;
}
if (arcQ.length > 2) {
let el = arcQ.length;
2021-06-02 00:26:16 -04:00
let e1 = arcQ[0]; // first in arcQ
let e2 = arcQ[Math.floor(el/2)]; // mid in arcQ
let e3 = arcQ[el-1]; // last in arcQ
let e4 = arcQ[el-2]; // second last in arcQ
let e5 = arcQ[el-3]; // third last in arcQ
let cc = BASE.util.center2d(e1, e2, e3, 1); // find center
let lr = BASE.util.center2d(e3, e4, e5, 1); // find local radius
2021-02-04 21:35:42 -05:00
let dc = 0;
let radFault = false;
if (lr) {
let angle = 2 * Math.asin(dist/(2*lr.r));
radFault = Math.abs(angle) > Math.PI * 2 / arcRes; // enforce arcRes(olution)
if (arcQ.center && arcQ.center.length > 1) {
let avg = arcQ.rSum / arcQ.center.length;
radFault = radFault || Math.abs(avg - lr.r) / avg > arcDev; // eliminate sharps and flats when local rad is out of arcDev(iation)
}
} else {
radFault = true;
}
2021-05-31 22:44:13 -04:00
if (cc) {
if ([cc.x,cc.y,cc.z,cc.r].hasNaN()) {
console.log({cc, e1, e2, e3});
}
if (arcQ.length === 3) {
arcQ.center = [ cc ];
arcQ.xSum = cc.x;
arcQ.ySum = cc.y;
arcQ.rSum = cc.r;
2021-05-31 22:44:13 -04:00
} else {
// check center point delta
let dx = cc.x - arcQ.xSum / arcQ.center.length;
let dy = cc.y - arcQ.ySum / arcQ.center.length;
2021-05-31 22:44:13 -04:00
dc = Math.sqrt(dx * dx + dy * dy);
}
// if new point is off the arc
// if (deem || depm || desp || dc > arcDist || cc.r < arcMin || cc.r > arcMax || dist > cc.r) {
if (deem || depm || desp || dc * arcQ.center.length / arcQ.rSum > arcDist || dist > cc.r || cc.r > arcMax || radFault) {
2021-05-31 22:44:13 -04:00
// console.log({dc, depm, desp});
if (arcQ.length === 4) {
// not enough points for an arc, drop first point and recalc center
emitQrec(arcQ.shift());
let tc = BASE.util.center2d(arcQ[0], arcQ[1], arcQ[2], 1);
// the new center is invalid as well. drop the first point
if (!tc) {
emitQrec(arcQ.shift());
} else {
arcQ.center = [ tc ];
}
2021-05-31 22:44:13 -04:00
} else {
// enough to consider an arc, emit and start new arc
let defer = arcQ.pop();
drainQ();
// re-add point that was off the last arc
arcQ.push(defer);
}
2021-02-04 21:35:42 -05:00
} else {
2021-05-31 22:44:13 -04:00
// new point is on the arc
arcQ.center.push(cc);
arcQ.xSum += cc.x;
arcQ.ySum += cc.y;
arcQ.rSum += cc.r;
2021-02-04 21:35:42 -05:00
}
} else {
2021-05-31 22:44:13 -04:00
// drainQ on invalid center
drainQ();
2021-02-04 21:35:42 -05:00
}
}
} else {
emitMM = emitPerMM * out.emit * dist;
moveTo({x:x, y:y, e:emitMM}, speedMMM);
emitted += emitMM;
}
2020-11-05 18:29:04 -05:00
} else {
2021-02-04 21:35:42 -05:00
drainQ();
2020-11-05 18:29:04 -05:00
moveTo({x:x, y:y}, seekMMM);
// TODO disabling out of plane z moves until a better mechanism
// can be built that doesn't rely on computed zpos from layer heights...
// when making z moves (like polishing) allow slowdown vs fast seek
// let moveSpeed = (lastp && lastp.z !== z) ? speedMMM : seekMMM;
// moveTo({x:x, y:y, z:z}, moveSpeed);
}
// retract filament if point retract flag set
2021-01-24 18:35:19 -05:00
if (out.retract) {
2021-02-04 21:35:42 -05:00
drainQ();
2020-11-05 18:29:04 -05:00
retract(zhop);
}
// update time and distance (should calc in moveTo() instead)
time += (dist / speedMMM) * 60 * 1.5;
distance += dist;
subst.progress = progress = Math.round((distance / totaldistance) * 100);
// emit tracked progress
if (gcodeTrack && progress != lastProgress) {
appendAllSub(gcodeTrack);
lastProgress = progress;
}
lastp = out.point;
laste = out.emit;
}
layer++;
// end open loop when detected
if (endloop) {
append(`M808`);
inLoop = undefined;
}
drainQ();
2020-11-05 18:29:04 -05:00
}
2021-02-04 21:35:42 -05:00
function emitQrec(rec) {
let {e, x, y, dist, emitPerMM, speedMMM} = rec;
emitMM = emitPerMM * e * dist;
moveTo({x:x, y:y, e:emitMM}, speedMMM);
emitted += emitMM;
}
function drainQ() {
if (!arcDist) {
return;
}
if (arcQ.length > 4) {
2021-06-11 13:38:00 -04:00
let vec1 = new THREE.Vector2(arcQ[1].x - arcQ[0].x, arcQ[1].y - arcQ[0].y);
let vec2 = new THREE.Vector2(arcQ.center[0].x - arcQ[0].x, arcQ.center[0].y - arcQ[0].y);
2021-02-04 21:35:42 -05:00
let from = arcQ[0];
let to = arcQ.peek();
let cl = arcQ.center.length;
let cc = {x:arcQ.xSum/cl, y:arcQ.ySum/cl, z:arcQ[0].z, r:arcQ.rSum/cl};
2021-02-04 21:35:42 -05:00
// first arc point
emitQrec(from);
// console.log(arcQ.slice(), arcQ.center);
// console.log({first: from, last: arcQ.peek(), center: cc});
2021-02-04 21:35:42 -05:00
// rest of arc to final point
let dist = arcQ.slice(1).map(v => v.dist).reduce((a,v) => a+v);
let emit = from.e;//arcQ.slice(1).map(v => v.e).reduce((a,v) => a+v);
emit = (from.emitPerMM * emit * dist);
outputLength += emit;
emitted += emit;
if (extrudeAbs) {
emit = outputLength;
}
2021-06-11 13:38:00 -04:00
let gc = vec1.cross(vec2) < 0 ? 'G2' : 'G3';
// XYR form
// let pre = `${gc} X${to.x.toFixed(decimals)} Y${to.y.toFixed(decimals)} R${cc.r.toFixed(decimals)} E${emit.toFixed(decimals)}`;
// XYIJ form
let pre = `${gc} X${to.x.toFixed(decimals)} Y${to.y.toFixed(decimals)} I${(cc.x - pos.x).toFixed(decimals)} J${(cc.y - pos.y).toFixed(decimals)} E${emit.toFixed(decimals)}`;
2021-02-04 21:35:42 -05:00
let add = pos.f !== from.speedMMM ? ` E${from.speedMMM}` : '';
2021-02-06 16:07:56 -05:00
append(`${pre}${add} ; merged=${cl-1} len=${dist.toFixed(decimals)} cp=${cc.x.round(2)},${cc.y.round(2)}`);
2021-02-04 21:35:42 -05:00
pos.x = to.x;
pos.y = to.y;
pos.z = to.z;
} else {
for (let rec of arcQ) {
emitQrec(rec);
}
}
arcQ.length = 0;
arcQ.center = undefined;
}
2020-11-05 18:29:04 -05:00
if (inLoop) {
append(`M808`);
}
2020-11-05 18:29:04 -05:00
subst.material = UTIL.round(emitted,2);
subst.time = UTIL.round(time,2);
2021-04-21 22:30:42 -04:00
subst['print_time'] = subst.time;
2020-11-05 18:29:04 -05:00
append("; --- shutdown ---");
appendAllSub(device.gcodePost);
append(`; --- filament used: ${subst.material} mm ---`);
append(`; --- print time: ${time.toFixed(0)}s ---`);
// force emit of buffer
append();
print.distance = emitted;
print.lines = lines;
print.bytes = bytes + lines - 1;
print.time = time;
if (debug) {
console.log('minz', minz);
}
2020-11-05 18:29:04 -05:00
};
})();