add intra-top routing to minimize retractions when possible

This commit is contained in:
Stewart Allen 2021-03-12 12:39:36 -05:00
commit 5f36260772
5 changed files with 149 additions and 8 deletions

View file

@ -471,7 +471,7 @@
if (options.onfirst) { if (options.onfirst) {
options.onfirst(point); options.onfirst(point);
} }
// move from startPoint to point // move to first output point on poly
addOutput(output, point, 0, moveSpeed, tool); addOutput(output, point, 0, moveSpeed, tool);
first = false; first = false;
} else { } else {
@ -564,18 +564,134 @@
} }
function intersectsTop(p1, p2) { function intersectsTop(p1, p2) {
return retractRequired(p1, p2);
let int = false; let int = false;
POLY.flatten(slice.topPolys().clone(true)).forEach(function(poly) { POLY.flatten(slice.topPolys().clone(true)).forEach(function(poly) {
if (!int) poly.forEachSegment(function(s1, s2) { if (!int) poly.forEachSegment(function(s1, s2) {
if (UTIL.intersect(p1,p2,s1,s2,BASE.key.SEGINT)) { if (UTIL.intersect(p1,p2,s1,s2,BASE.key.SEGINT)) {
int = true; return int = true;
return int;
} }
}); });
}); });
return int; return int;
} }
// returns true if no path around and retract required
// returns false if routed around or no retract
function retractRequired(p1, p2) {
const dbug = false;
let ints = [];
let tops = POLY.flatten(slice.topPolys().clone(true));
for (let poly of tops) {
poly.forEachSegment(function(s1, s2) {
let ip = UTIL.intersect(p1,p2,s1,s2,BASE.key.SEGINT);
if (ip) {
ints.push({ip, poly});
}
});
}
// odd # of intersections ?!? do retraction
if (ints.length && ints.length % 2 !== 0) {
if (dbug === slice.index) console.log(slice.index, {odd_intersects: ints});
return true;
}
// sort by distance
ints.sort((a, b) => {
return a.ip.dist - b.ip.dist;
});
let valid = ints.length;
// check pairs. eliminate too close points.
// pairs must intersect same poly or retract.
for (let i=0; i<ints.length; i += 2) {
let i1 = ints[0];
let i2 = ints[1];
// different poly. force retract
if (i1.poly !== i2.poly) {
if (dbug === slice.index) console.log(slice.index, {int_diff_poly: ints, i});
return true;
}
if (i1.ip.distTo2D(i2.ip) < retractDist) {
if (dbug === slice.index) console.log(slice.index, {int_dist_too_small: i1.ip.distTo2D(i2.ip), retractDist});
valid -= 2;
}
}
if (valid > 2) {
if (dbug === slice.index) console.log(slice.index, {complex_route: valid});
return true;
}
if (valid) {
// can route around intersected top polys
for (let i=0; i<ints.length; i += 2) {
let i1 = ints[0];
let i2 = ints[1];
// output first point
addOutput(preout, i1.ip, 0, moveSpeed, extruder);
// create two loops around poly
// find shortest of two paths and emit poly points
let poly = i1.poly;
let isCW = poly.isClockwise();
let points = poly.points;
let p1p = isCW ? points : points.slice().reverse(); // CW
let p2p = isCW ? points.slice().reverse() : points; // CCW
let r1s = p1p.indexOf(isCW ? i1.ip.p2 : i1.ip.p1);
let r1e = p1p.indexOf(isCW ? i2.ip.p1 : i2.ip.p2);
let r1 = r1s === r1e ?
[ p1p[r1s] ] : r1s < r1e ?
[ ...p1p.slice(r1s,r1e+1) ] :
[ ...p1p.slice(r1s), ...p1p.slice(0,r1e+1) ];
let r1d = 0;
for (let i=1; i<r1.length; i++) {
r1d += r1[i-1].distTo2D(r1[i]);
}
let r2s = p2p.indexOf(isCW ? i1.ip.p1 : i1.ip.p2);
let r2e = p2p.indexOf(isCW ? i2.ip.p2 : i2.ip.p1);
let r2 = r2s === r2e ?
[ p2p[r2s] ] : r2s < r2e ?
[ ...p2p.slice(r2s,r2e+1) ] :
[ ...p2p.slice(r2s), ...p2p.slice(0,r2e+1) ];
let r2d = 0;
for (let i=1; i<r2.length; i++) {
r2d += r2[i-1].distTo2D(r2[i]);
}
let route = r1d <= r2d ? r1 : r2;
if (dbug === slice.index) console.log(slice.index, {
ints: ints.map(i=>i.ip.dist),
i1, i2, same: i1.poly === i2.poly,
route,
r1, r1d, r1s, r1e,
r2, r2d, r2s, r2e,
isCW});
for (let p of route) {
addOutput(preout, p, 0, moveSpeed, extruder);
}
// output last point
addOutput(preout, i2.ip, 0, moveSpeed, extruder);
}
}
return false;
}
function outputTraces(poly, opt = {}) { function outputTraces(poly, opt = {}) {
if (!poly) return; if (!poly) return;
if (Array.isArray(poly)) { if (Array.isArray(poly)) {
@ -631,7 +747,9 @@
onfirst: function(firstPoint) { onfirst: function(firstPoint) {
let from = seedPoint || startPoint; let from = seedPoint || startPoint;
if (from.distTo2D(firstPoint) > retractDist) { if (from.distTo2D(firstPoint) > retractDist) {
retract(); if (intersectsTop(from, firstPoint)) {
retract();
}
} }
seedPoint = null; seedPoint = null;
} }

View file

@ -119,6 +119,11 @@
clearTimeout(int); clearTimeout(int);
} }
}, 50); }, 50);
// let slider = $('top-slider');
// slider.style.display = 'flex';
// slider.oninput = slider.onchange = (ev) => {
// api.const.STACKS.setFraction(parseInt(ev.target.value)/100);
// };
}); });
api.event.on("mode.set", mode => { api.event.on("mode.set", mode => {
isFdmMode = mode === 'FDM'; isFdmMode = mode === 'FDM';

View file

@ -587,6 +587,8 @@
const headColor = 0x888888; const headColor = 0x888888;
const moveColor = opts.move >= 0 ? opts.move : 0xaaaaaa; const moveColor = opts.move >= 0 ? opts.move : 0xaaaaaa;
const printColor = opts.print >= 0 ? opts.print : 0x777700; const printColor = opts.print >= 0 ? opts.print : 0x777700;
const arrowAll = false;
const arrowSize = arrowAll ? 0.2 : 0.4;
const layers = []; const layers = [];
const moveOpt = { const moveOpt = {
@ -613,6 +615,7 @@
let lastOut = null; let lastOut = null;
let current = null; let current = null;
let retracted = false; let retracted = false;
let retractz = 0;
function color(point) { function color(point) {
return FDM.rateToColor(point.speed, maxspd); return FDM.rateToColor(point.speed, maxspd);
@ -648,6 +651,7 @@
if (out.retract) { if (out.retract) {
retracts.push(out.point); retracts.push(out.point);
retracted = true; retracted = true;
retractz++;
} }
if (!out.point) { if (!out.point) {
// in cam mode, these are drilling or dwell ops // in cam mode, these are drilling or dwell ops
@ -655,7 +659,7 @@
} }
if (lastOut) { if (lastOut) {
if (lastOut.emit !== out.emit) { if (arrowAll || lastOut.emit !== out.emit) {
heads.push({p1: lastOut.point, p2: out.point}); heads.push({p1: lastOut.point, p2: out.point});
} }
const op = out.point, lp = lastOut.point; const op = out.point, lp = lastOut.point;
@ -720,8 +724,8 @@
const slope = p2.slopeTo(p1); const slope = p2.slopeTo(p1);
const s1 = BASE.newSlopeFromAngle(slope.angle + 20); const s1 = BASE.newSlopeFromAngle(slope.angle + 20);
const s2 = BASE.newSlopeFromAngle(slope.angle - 20); const s2 = BASE.newSlopeFromAngle(slope.angle - 20);
const p3 = points.p2.projectOnSlope(s1, 0.8); const p3 = points.p2.projectOnSlope(s1, arrowSize);
const p4 = points.p2.projectOnSlope(s2, 0.8); const p4 = points.p2.projectOnSlope(s2, arrowSize);
return newPolygon().addPoints([p2,p3,p4]).setZ(p2.z + 0.01); return newPolygon().addPoints([p2,p3,p4]).setZ(p2.z + 0.01);
}), { thin: true, outline: true }); }), { thin: true, outline: true });
} }
@ -753,7 +757,7 @@
update(index / levels.length, output); update(index / levels.length, output);
}); });
console.log({retractz});
return layers; return layers;
} }

View file

@ -1244,6 +1244,17 @@ th, tr, td, label {
width: 20px; width: 20px;
} }
#top-slider {
position: absolute;
display: none;
top: 60px;
left: 50px;
right: 50px;
}
#anim-slider {
width: 100%;
}
#alert-area { #alert-area {
display: none; display: none;
justify-content: center; justify-content: center;

View file

@ -461,6 +461,9 @@
<div id="alert-text">alerts<br>alerts<br>alerts</div> <div id="alert-text">alerts<br>alerts<br>alerts</div>
</div> </div>
</div> </div>
<div id="top-slider" class="f-col grow">
<input id="anim-slider" type="range" min="0" max="1000" value="0"></input>
</div>
</div> </div>
</body> </body>
</html> </html>