fix scarf/arc conflict and scarf z on export. add print remain time macro var

This commit is contained in:
Stewart Allen 2025-09-28 02:08:32 -04:00
commit 77b4cce97a
5 changed files with 67 additions and 44 deletions

View file

@ -100,11 +100,12 @@
* subfolder parameter for dropped files * subfolder parameter for dropped files
* auto-kick check box in preferences * auto-kick check box in preferences
# Mesh:Tool # Mesh:Tool
* add undo/redo * add undo/redo
* add TextGeometry * add TextGeometry
* https://threejs.org/docs/#examples/en/geometries/TextGeometry
* https://dustinpfister.github.io/2023/07/05/threejs-text-geometry/
* font to path with https://github.com/paulzi/svg-text-to-path * font to path with https://github.com/paulzi/svg-text-to-path
* click to repair normals based on a known good (selected) face * click to repair normals based on a known good (selected) face
* send to Kiri:Moto workspace (or update model vertices in place) * send to Kiri:Moto workspace (or update model vertices in place)
@ -116,3 +117,7 @@
* fix mirror to work with groups (just models currently) * fix mirror to work with groups (just models currently)
* add analyze results dialog * add analyze results dialog
* remove/hide auto-repair function * remove/hide auto-repair function
# Other
* preferred icons https://icons.getbootstrap.com/

View file

@ -80,11 +80,9 @@ class Print {
return lastOut; return lastOut;
} }
addPrintPoints(input, output, startPoint, tool) { addPrintPoints(input, output) {
if (this.startPoint && input.length > 0) { if (this.startPoint && input.length > 0) {
this.lastPoint = this.startPoint; this.lastPoint = this.startPoint;
// TODO: revisit seek to origin as the first move
// addOutput(output, startPoint, 0, undefined, tool);
} }
output.appendAll(input); output.appendAll(input);
} }
@ -120,11 +118,11 @@ class Print {
const { settings } = scope; const { settings } = scope;
const { process } = settings; const { process } = settings;
let shortDist = process.outputShortDistance, let shellMult = numOrDefault(options.extrude, process.outputShellMult),
shellMult = numOrDefault(options.extrude, process.outputShellMult),
printSpeed = options.rate || process.outputFeedrate, printSpeed = options.rate || process.outputFeedrate,
moveSpeed = process.outputSeekrate, moveSpeed = process.outputSeekrate,
minSpeed = process.outputMinSpeed, minSpeed = process.outputMinSpeed,
nozzleSize = options.nozzleSize,
coastDist = options.coast || 0, coastDist = options.coast || 0,
closest = options.simple ? poly.first() : poly.findClosestPointTo(startPoint), closest = options.simple ? poly.first() : poly.findClosestPointTo(startPoint),
perimeter = poly.perimeter(), perimeter = poly.perimeter(),
@ -177,20 +175,20 @@ class Print {
scarf -= d; scarf -= d;
if (scarf <= 0) break; if (scarf <= 0) break;
} }
let scale = 0.25; // flow compensation on overlap let fcs = 1.0; // flow compensation seam
let mid = (1 / sp.length) * 0.75; // flow compensation (- half step) let fco = (1 / sp.length) * 0.0; // flow compensation offset (- half step)
let zd = (epz - spz) / sp.length; let zd = (epz - spz) / sp.length;
let zi = 1; let zi = 1;
for (let p of sp) { for (let p of sp) {
p.z -= zd * (sp.length - zi); p.z -= zd * (sp.length - zi);
p.moved = (((zi++) / sp.length) * scale) - 1 - mid; p.moved = (((zi++) / sp.length) * fcs) - 1 - fco;
} }
let esp = sp.map(p => p.clone()); // ending scarf points let esp = sp.map(p => p.clone()); // ending scarf points
for (let p of esp) { for (let p of esp) {
p.z = epz; p.z = epz;
p.moved = (((--zi) / esp.length) * scale) - 1 - mid; p.moved = (((--zi) / esp.length) * fcs) - 1 - fco;
} }
esp.pop(); // stop short to prevent overlap bulge // esp.pop(); // stop short to prevent overlap bulge
pp.push(...esp); pp.push(...esp);
// console.log({ poly, spz, epz, zd, sp, esp }); // console.log({ poly, spz, epz, zd, sp, esp });
scarf = true; scarf = true;
@ -208,7 +206,7 @@ class Print {
} else if (first) { } else if (first) {
// if (point.skip) console.log({ skip: point }); // if (point.skip) console.log({ skip: point });
if (options.onfirst) { if (options.onfirst) {
options.onfirst(point); options.onfirst(point, output);
} }
// move to first output point on poly // move to first output point on poly
let out = scope.addOutput(output, point, 0, moveSpeed, tool); let out = scope.addOutput(output, point, 0, moveSpeed, tool);

View file

@ -59,7 +59,8 @@ export function fdm_export(print, online, ondone, ondebug) {
retSpeed = process.outputRetractSpeed * 60 || 1, // range retSpeed = process.outputRetractSpeed * 60 || 1, // range
retDwell = process.outputRetractDwell || 0, // range retDwell = process.outputRetractDwell || 0, // range
timeDwell = retDwell / 1000, timeDwell = retDwell / 1000,
arcDist = isBelt ? 0 : (process.arcTolerance || 0), scarfZ = process.outputScarfLength ? true : false,
arcDist = isBelt || scarfZ ? 0 : (process.arcTolerance || 0),
arcMin = 1, arcMin = 1,
arcRes = 20, arcRes = 20,
arcDev = 0.5, arcDev = 0.5,
@ -113,7 +114,9 @@ export function fdm_export(print, online, ondone, ondebug) {
tool: tool, tool: tool,
oid: '', oid: '',
oname: '', oname: '',
model_labels: model_labels.sort().join(',') model_labels: model_labels.sort().join(','),
total_time: Math.ceil(print.total_time / 60),
remain_time: Math.ceil(print.total_time / 60),
}, },
pidx, path, out, speedMMM, emitMM, emitPerMM, lastp, laste, dist, pidx, path, out, speedMMM, emitMM, emitPerMM, lastp, laste, dist,
lines = 0, lines = 0,
@ -527,6 +530,7 @@ export function fdm_export(print, online, ondone, ondebug) {
// retract before first move // retract before first move
retract(); retract();
subst.remain_time = Math.ceil(print.total_time / 60);
while (layer < layers.length) { while (layer < layers.length) {
path = layers[layer]; path = layers[layer];
layerno = path.slice.index; layerno = path.slice.index;
@ -600,7 +604,7 @@ export function fdm_export(print, online, ondone, ondebug) {
} }
// move Z to layer height // move Z to layer height
if (layer > 0 || !isBelt) { if (layer === 0 || ((layer > 0 || !isBelt) && !scarfZ)) {
moveTo({z:zpos}, seekMMM); moveTo({z:zpos}, seekMMM);
} }
@ -783,12 +787,20 @@ export function fdm_export(print, online, ondone, ondebug) {
} else { } else {
// emitMM = emitPerMM * out.emit * dist; // emitMM = emitPerMM * out.emit * dist;
emitMM = extrudeMM(dist, emitPerMM, out.emit); emitMM = extrudeMM(dist, emitPerMM, out.emit);
moveTo({x:x, y:y, e:emitMM}, speedMMM); if (scarfZ) {
moveTo({x, y, z:z + path.height/2, e:emitMM}, speedMMM);
} else {
moveTo({x, y, e:emitMM}, speedMMM);
}
emitted += emitMM; emitted += emitMM;
} }
} else { } else {
drainQ(); drainQ();
moveTo({x:x, y:y}, seekMMM); if (scarfZ) {
moveTo({x, y, z:z + path.height/2, e:emitMM}, speedMMM);
} else {
moveTo({x, 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...
// when making z moves (like polishing) allow slowdown vs fast seek // when making z moves (like polishing) allow slowdown vs fast seek
@ -834,11 +846,13 @@ export function fdm_export(print, online, ondone, ondebug) {
append(`M808`); append(`M808`);
} }
drainQ(); drainQ();
print.total_time -= path.print_time;
subst.remain_time = Math.ceil(print.total_time / 60);
} }
function emitQrec(rec) { function emitQrec(rec) {
let {e, x, y, dist, emitPerMM, speedMMM} = rec; let {e, x, y, dist, emitPerMM, speedMMM} = rec;
// emitMM = emitPerMM * e * dist;
emitMM = extrudeMM(dist, emitPerMM, e); emitMM = extrudeMM(dist, emitPerMM, e);
moveTo({x:x, y:y, e:emitMM}, speedMMM); moveTo({x:x, y:y, e:emitMM}, speedMMM);
emitted += emitMM; emitted += emitMM;
@ -962,7 +976,6 @@ export function fdm_export(print, online, ondone, ondebug) {
} }
return true; return true;
} }
if (inloops) { if (inloops) {

View file

@ -142,6 +142,7 @@ export async function fdm_prepare(widgets, settings, update) {
}); });
layerout.z = zoff + height; layerout.z = zoff + height;
layerout.height = height; layerout.height = height;
layerout.print_time = printPoint.layer_time;
output.append(layerout); output.append(layerout);
layerout = []; layerout = [];
@ -196,7 +197,7 @@ export async function fdm_prepare(widgets, settings, update) {
}); });
}); });
print.addPrintPoints(preout, layerout, null); print.addPrintPoints(preout, layerout);
if (preout.length) { if (preout.length) {
// retract between brims and print // retract between brims and print
@ -472,6 +473,7 @@ export async function fdm_prepare(widgets, settings, update) {
let lastOut; let lastOut;
print.zmax = zmax; print.zmax = zmax;
print.total_time = 0;
// walk cake layers bottom up // walk cake layers bottom up
for (let layer of cake) { for (let layer of cake) {
@ -574,6 +576,8 @@ export async function fdm_prepare(widgets, settings, update) {
} }
} }
); );
layerout.print_time = printPoint.layer_time;
print.total_time += printPoint.layer_time;
print.setWidget(null); print.setWidget(null);
lastOut = slice; lastOut = slice;
@ -1084,6 +1088,7 @@ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) {
} }
} else { } else {
let finishShell = poly.depth === 0 && !firstLayer; let finishShell = poly.depth === 0 && !firstLayer;
let scarf = (slice.index > 0 && traceNo === 0 && z - startPoint?.z > 1e-3) ? scarfLength : 0;
startPoint = print.polyPrintPath(poly, startPoint, preout, { startPoint = print.polyPrintPath(poly, startPoint, preout, {
accel: finishShell, accel: finishShell,
ccw: opt.shell && process.outputAlternating && slice.index % 2, ccw: opt.shell && process.outputAlternating && slice.index % 2,
@ -1091,10 +1096,9 @@ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) {
extrude: numOrDefault(opt.extrude, shellMult), extrude: numOrDefault(opt.extrude, shellMult),
nozzleSize, nozzleSize,
rate: finishShell ? finishSpeed : printSpeed, rate: finishShell ? finishSpeed : printSpeed,
scarf: (traceNo === 0 && z - startPoint?.z > 1e-3) ? scarfLength : 0, scarf,
tool: extruder, tool: extruder,
wipe: process.outputWipeDistance || 0, onfirst: (firstPoint, preout) => {
onfirst: function(firstPoint) {
let from = seedPoint || startPoint; let from = seedPoint || startPoint;
if (from.distTo2D(firstPoint) > retractDist) { if (from.distTo2D(firstPoint) > retractDist) {
if (intersectsTop(from, firstPoint)) { if (intersectsTop(from, firstPoint)) {
@ -1576,23 +1580,21 @@ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) {
// adjust layer output speeds (by slowing them down) // adjust layer output speeds (by slowing them down)
// if layer print time is less than minimum (required for cooling) // if layer print time is less than minimum (required for cooling)
if (minLayerTime) { let lp, td = 0, tt = 0;
let lp, td = 0, tt = 0; for (let p of preout) {
for (let p of preout) { if (!p.emit) continue;
if (!p.emit) continue; let mms = p.speed ?? 1;
let mms = p.speed ?? 1; let dst = lp?.distTo2D(p.point) ?? 0;
let dst = lp?.distTo2D(p.point) ?? 0; if (dst) {
if (dst) { tt += (dst/mms);
tt += (dst/mms); td += dst;
td += dst;
}
lp = p.point;
} }
if (tt < minLayerTime) { lp = p.point;
let fact = tt / minLayerTime; }
for (let p of preout) { if (minLayerTime && tt < minLayerTime) {
if (p.emit) p.speed *= fact; let fact = tt / minLayerTime;
} for (let p of preout) {
if (p.emit) p.speed *= fact;
} }
} }
@ -1602,7 +1604,12 @@ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) {
} }
// add offset points to total print // add offset points to total print
print.addPrintPoints(preout, output, origin, extruder); print.addPrintPoints(preout, output);
return startPoint.add(offset); // create next layer start point and annotate
// with print time for previous layer (hack to
// avoid changing return signature rn)
let newStart = startPoint.add(offset);
newStart.layer_time = Math.max(tt, minLayerTime);
return newStart;
} }

View file

@ -865,11 +865,11 @@ self.lang['en-us'] = {
ad_mins_s: "min speed", ad_mins_s: "min speed",
ad_mins_l: ["minimum speed","for short segments"], ad_mins_l: ["minimum speed","for short segments"],
ad_scar_s: "scarf length", ad_scar_s: "scarf length",
ad_scar_l: ["ease up length for scarf joint","0 = disabled"], ad_scar_l: ["ease up length for scarf joint. disables arc detection","0 = disabled"],
ad_spol_s: "short path", ad_spol_s: "short path",
ad_spol_l: ["polygons shorter than this","will have their print speed","scaled down to min speed","in millimeters"], ad_spol_l: ["polygons shorter than this","will have their print speed","scaled down to min speed","in millimeters"],
ad_arct_s: "arc tolerance", ad_arct_s: "arc tolerance",
ad_arct_l: ["convert faceted lines to arcs","center point drift tolerance","when matching arc points","consider values around 0.15","in millimeters","0 to disable"], ad_arct_l: ["convert faceted lines to arcs","center point drift tolerance","when matching arc points","consider values around 0.15","value in millimeters","0 or scarf disables this"],
ad_zhop_s: "z hop distance", ad_zhop_s: "z hop distance",
ad_zhop_l: ["amount to raise z","on retraction moves","in millimeters","0 to disable"], ad_zhop_l: ["amount to raise z","on retraction moves","in millimeters","0 to disable"],
ad_abkl_s: "anti-backlash", ad_abkl_s: "anti-backlash",