checkpoint arc generation on export

This commit is contained in:
Stewart Allen 2021-02-04 21:35:42 -05:00
commit b23a38ce86
7 changed files with 156 additions and 8 deletions

View file

@ -356,7 +356,7 @@
* return circle center given three points * return circle center given three points
* from https://stackoverflow.com/questions/4103405/what-is-the-algorithm-for-finding-the-center-of-a-circle-from-three-points * from https://stackoverflow.com/questions/4103405/what-is-the-algorithm-for-finding-the-center-of-a-circle-from-three-points
*/ */
function center2d(A,B,C) { function center2d(A,B,C,rad) {
let yDelta_a = B.y - A.y, let yDelta_a = B.y - A.y,
xDelta_a = B.x - A.x, xDelta_a = B.x - A.x,
yDelta_b = C.y - B.y, yDelta_b = C.y - B.y,
@ -366,7 +366,11 @@
center = {x:0, y:0, z:0}; center = {x:0, y:0, z:0};
center.x = (aSlope*bSlope*(A.y - C.y) + bSlope*(A.x + B.x) - aSlope*(B.x+C.x) )/(2* (bSlope-aSlope) ); center.x = (aSlope*bSlope*(A.y - C.y) + bSlope*(A.x + B.x) - aSlope*(B.x+C.x) )/(2* (bSlope-aSlope) );
center.y = -1*(center.x - (A.x+B.x)/2)/aSlope + (A.y+B.y)/2; center.y = -1*(center.x - (A.x+B.x)/2)/aSlope + (A.y+B.y)/2;
if (rad) {
let dx = center.x - A.x;
let dy = center.y - A.y;
center.r = Math.sqrt(dx*dx + dy*dy)
}
return center; return center;
} }

View file

@ -666,6 +666,16 @@
return this; return this;
}; };
PRO.addObj = function(obj) {
if (Array.isArray(obj)) {
for (let o of obj) {
this.addObj(o);
}
return this;
}
return this.add(obj.x, obj.y, obj.z);
}
/** /**
* append array of points to polygon and return polygon * append array of points to polygon and return polygon
* *

View file

@ -343,6 +343,7 @@
sliceMinHeight: 0, sliceMinHeight: 0,
sliceAdaptive: false, sliceAdaptive: false,
zHopDistance: 0.2, zHopDistance: 0.2,
arcTolerance: 0,
antiBacklash: 1, antiBacklash: 1,
gcodePause: "" gcodePause: ""
} }

View file

@ -1783,6 +1783,7 @@
outputCoastDist: UC.newInput(LANG.ad_scst_s, {title:LANG.ad_scst_l, bound:UC.bound(0.0,10), convert:UC.toFloat, modes:FDM}), outputCoastDist: UC.newInput(LANG.ad_scst_s, {title:LANG.ad_scst_l, bound:UC.bound(0.0,10), convert:UC.toFloat, modes:FDM}),
fdmSep: UC.newBlank({class:"pop-sep", modes:FDM}), fdmSep: UC.newBlank({class:"pop-sep", modes:FDM}),
zHopDistance: UC.newInput(LANG.ad_zhop_s, {title:LANG.ad_zhop_l, bound:UC.bound(0,3.0), convert:UC.toFloat, modes:FDM}), zHopDistance: UC.newInput(LANG.ad_zhop_s, {title:LANG.ad_zhop_l, bound:UC.bound(0,3.0), convert:UC.toFloat, modes:FDM}),
arcTolerance: UC.newInput(LANG.ad_arct_s, {title:LANG.ad_arct_l, bound:UC.bound(0,1.0), convert:UC.toFloat, modes:FDM, show:isNotBelt}),
antiBacklash: UC.newInput(LANG.ad_abkl_s, {title:LANG.ad_abkl_l, bound:UC.bound(0,3), convert:UC.toInt, modes:FDM}), antiBacklash: UC.newInput(LANG.ad_abkl_s, {title:LANG.ad_abkl_l, bound:UC.bound(0,3), convert:UC.toInt, modes:FDM}),
fdmSep: UC.newBlank({class:"pop-sep", modes:FDM}), fdmSep: UC.newBlank({class:"pop-sep", modes:FDM}),
gcodePauseLayers: UC.newInput(LANG.ag_paws_s, {title:LANG.ag_paws_l, modes:FDM, comma:true}), gcodePauseLayers: UC.newInput(LANG.ag_paws_s, {title:LANG.ag_paws_l, modes:FDM, comma:true}),

View file

@ -139,6 +139,20 @@
const beltaxis = { X: "X", Y: "Z", Z: "Y", E: "E", F: "F" }; const beltaxis = { X: "X", Y: "Z", Z: "Y", E: "E", F: "F" };
const beltfact = Math.cos(Math.PI/4); const beltfact = Math.cos(Math.PI/4);
function G2G3(g2, line) {
const rec = {};
line.forEach(function(tok) {
rec[tok.charAt(0)] = parseFloat(tok.substring(1));
});
console.log({g2, arc: line, pos});
pos.X = rec.X;
pos.Y = rec.Y;
pos.Z = rec.Z;
}
function G0G1(g0, line) { function G0G1(g0, line) {
const mov = {}; const mov = {};
@ -284,6 +298,14 @@
case 'G1': case 'G1':
G0G1(false, line); G0G1(false, line);
break; break;
case 'G2':
// turn arc into a series of points
G2G3(true, line)
break;
case 'G3':
// turn arc into a series of points
G2G3(false, line);
break;
case 'M6': case 'M6':
tool = parseInt(line[0].substring(1)); tool = parseInt(line[0].substring(1));
break; break;

View file

@ -33,7 +33,7 @@
pause = [], pause = [],
pauseCmd = device.gcodePause, pauseCmd = device.gcodePause,
output = [], output = [],
outputLength = 0, outputLength = 0, // absolute extruder position
lastProgress = 0, lastProgress = 0,
decimals = BASE.config.gcode_decimals || 4, decimals = BASE.config.gcode_decimals || 4,
progress = 0, progress = 0,
@ -50,6 +50,7 @@
retSpeed = process.outputRetractSpeed * 60, retSpeed = process.outputRetractSpeed * 60,
retDwell = process.outputRetractDwell || 0, retDwell = process.outputRetractDwell || 0,
timeDwell = retDwell / 1000, timeDwell = retDwell / 1000,
arcDist = isBelt ? 0 : (process.arcTolerance || 0),
originCenter = process.outputOriginCenter, originCenter = process.outputOriginCenter,
offset = originCenter ? null : { offset = originCenter ? null : {
x: device.bedWidth/2, x: device.bedWidth/2,
@ -80,7 +81,9 @@
bcos = Math.cos(Math.PI/4), bcos = Math.cos(Math.PI/4),
icos = 1 / bcos, icos = 1 / bcos,
loops = process.outputLoopLayers, loops = process.outputLoopLayers,
inLoop; inLoop,
arcAt,
arcQ = [];
if (isBelt && loops) { if (isBelt && loops) {
loops = loops.split(',').map(range => { loops = loops.split(',').map(range => {
@ -392,6 +395,7 @@
// re-engage post-retraction before new extrusion // re-engage post-retraction before new extrusion
if (out.emit && retracted) { if (out.emit && retracted) {
drainQ();
// console.log({engage:zhop}); // console.log({engage:zhop});
// when enabled, resume previous Z // when enabled, resume previous Z
if (zhop && pos.z != zpos) moveTo({z:zpos}, seekMMM, "z-hop end"); if (zhop && pos.z != zpos) moveTo({z:zpos}, seekMMM, "z-hop end");
@ -404,10 +408,58 @@
} }
if (lastp && out.emit) { if (lastp && out.emit) {
if (arcDist) {
let rec = {e:out.emit, x, y, z, dist, emitPerMM, speedMMM};
arcQ.push(rec);
let deem = false;
let depm = false;
let desp = false;
if (arcQ.length > 1) {
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;
let e1 = arcQ[el-3];
let e2 = arcQ[el-2];
let e3 = arcQ[el-1];
let cc = BASE.util.center2d(e1, e2, e3, 1);
let dc = 0;
if (arcQ.length === 3) {
arcQ.center = [ cc ];
} else {
// check center point delta
let dx = cc.x - arcQ.center[0].x;
let dy = cc.y - arcQ.center[0].y;
dc = Math.sqrt(dx * dx + dy * dy);
}
// if new point is off the arc
if (deem || depm || desp || dc > arcDist) {
// console.log({dc, depm, desp});
if (arcQ.length === 4) {
// not enough points for an arc, drop first point and recalc center
emitQrec(arcQ.shift());
arcQ.center = [ BASE.util.center2d(arcQ[0], arcQ[1], arcQ[2], 1) ];
} 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);
}
} else {
// new point is on the arc
arcQ.center.push(cc);
}
}
} else {
emitMM = emitPerMM * out.emit * dist; emitMM = emitPerMM * out.emit * dist;
moveTo({x:x, y:y, e:emitMM}, speedMMM); moveTo({x:x, y:y, e:emitMM}, speedMMM);
emitted += emitMM; emitted += emitMM;
}
} else { } else {
drainQ();
moveTo({x:x, y:y}, seekMMM); moveTo({x:x, y:y}, seekMMM);
// TODO disabling out of plane z moves until a better mechanism // TODO disabling out of plane z moves until a better mechanism
// can be built that doesn't rely on computed zpos from layer heights... // can be built that doesn't rely on computed zpos from layer heights...
@ -418,6 +470,7 @@
// retract filament if point retract flag set // retract filament if point retract flag set
if (out.retract) { if (out.retract) {
drainQ();
retract(zhop); retract(zhop);
} }
@ -437,6 +490,61 @@
} }
layer++; layer++;
} }
drainQ();
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) {
let area = BASE.newPolygon().addObj(arcQ).area();
let from = arcQ[0];
let to = arcQ.peek();
let cc = {x:0, y:0, z:0, r:0};
let cl = arcQ.length;
for (let center of arcQ.center) {
cc.x += center.x;
cc.y += center.y;
cc.z += center.z;
cc.r += center.r;
}
cc.x /= cl;
cc.y /= cl;
cc.z /= cl;
cc.r /= cl;
// first arc point
emitQrec(from);
// 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;
}
let gc = area > 0 ? 'G2' : 'G3';
let pre = `${gc} X${to.x.toFixed(decimals)} Y${to.y.toFixed(decimals)} R${cc.r.toFixed(decimals)} E${emit.toFixed(decimals)}`;
let add = pos.f !== from.speedMMM ? ` E${from.speedMMM}` : '';
append(`${pre}${add} ; merged=${cl-1} dist=${dist.toFixed(decimals)}`);
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;
}
if (inLoop) { if (inLoop) {
append(`M808`); append(`M808`);

View file

@ -483,10 +483,12 @@ kiri.lang['en-us'] = {
ad_mins_l: "minimum speed\nfor short segments", ad_mins_l: "minimum speed\nfor short segments",
ad_spol_s: "short path", ad_spol_s: "short path",
ad_spol_l: "polygons shorter than this\nwill have their print speed\nscaled down to min speed\nin millimeters", ad_spol_l: "polygons shorter than this\nwill have their print speed\nscaled down to min speed\nin millimeters",
ad_arct_s: "arc tolerance",
ad_arct_l: "convert faceted lines to arcs\ncenter point drift tolerance\nwhen matching arc points\nconsider values around 0.15\nin millimeters\n0 to disable",
ad_zhop_s: "z hop dist", ad_zhop_s: "z hop dist",
ad_zhop_l: "amount to raise z\non retraction moves\nin millimeters\n0 to disable", ad_zhop_l: "amount to raise z\non retraction moves\nin millimeters\n0 to disable",
ad_abkl_s: "anti-backlash", ad_abkl_s: "anti-backlash",
ad_abkl_l: "use micro-movements to cancel\nbacklash during fills\nin millimeters", ad_abkl_l: "for better flat surface finish\nuse micro-movements to cancel\nbacklash in solid layer output\nin millimeters\n0 to disable",
ad_lret_s: "layer retract", ad_lret_s: "layer retract",
ad_lret_l: "force filament retraction\nbetween layers", ad_lret_l: "force filament retraction\nbetween layers",
ad_play_s: "polish layers", ad_play_s: "polish layers",