add new experimental thin fill

This commit is contained in:
Stewart Allen 2021-02-20 22:50:03 -05:00
commit bc33c71f34
8 changed files with 216 additions and 37 deletions

View file

@ -53,7 +53,7 @@
"origin_center": false,
"extrude_abs": true,
"bed_belt": true,
"bed_width": 215,
"bed_width": 220,
"bed_depth": 300,
"build_height": 170
},

View file

@ -15,7 +15,7 @@
function time() { return Date.now() }
function lerp(from, to, maxInc) {
function lerp(from, to, maxInc, incFrom) {
let dir = Math.sign(to - from);
let delta = Math.abs(to - from);
let steps = Math.floor(delta / maxInc);
@ -25,7 +25,7 @@
steps++;
per = delta / steps;
}
let out = [];
let out = incFrom ? [from] : [];
while (steps-- > 0) {
from += per * dir;
out.push(from);

View file

@ -260,6 +260,182 @@
return Math.abs(diff);
}
// generate center crossing point cloud
PRO.centers = function(step, z, min, max, opt = {}) {
let cloud = [],
bounds = this.bounds,
points = this.points,
length = points.length,
lines = opt.lines || false;
for (let y of UTIL.lerp(bounds.miny + 0.01, bounds.maxy - 0.01, step, true)) {
let ints = [];
for (let i=0; i<length; i++) {
let p1 = points[i % length];
let p2 = points[(i+1) % length];
if (
(p1.y <= y && p2.y > y) ||
(p1.y > y && p2.y <= y)
) ints.push([p1,p2]);
}
let cntr = [];
if (ints.length && ints.length % 2 === 0) {
for (let int of ints) {
let [p1, p2] = int;
if (p2.y < p1.y) {
let tp = p1;
p1 = p2;
p2 = tp;
}
let minx = Math.min(p1.x, p2.x);
let maxx = Math.max(p1.x, p2.x);
let miny = Math.min(p1.y, p2.y);
let maxy = Math.max(p1.y, p2.y);
let dx = p2.x - p1.x;
let dy = maxy - miny;
let pct = (y - miny) / dy;
let xpo = p1.x + pct * dx;
cntr.push(xpo);
}
}
cntr.sort((a, b) => {
return b - a;
});
let lp, eo = 0;
for (let x of cntr) {
let p = BASE.newPoint(x, y, z);
if (eo++ % 2) {
let d = lp.distTo2D(p);
if (d >= min && d <= max) {
if (lines) {
cloud.push(lp);
cloud.push(p);
} else {
cloud.push(BASE.newPoint(
(lp.x + p.x) / 2, y, z
));
}
}
} else {
lp = p;
}
}
}
for (let x of UTIL.lerp(bounds.minx + 0.01, bounds.maxx - 0.01, step, true)) {
let ints = [];
for (let i=0; i<length; i++) {
let p1 = points[i % length];
let p2 = points[(i+1) % length];
if (
(p1.x <= x && p2.x > x) ||
(p1.x > x && p2.x <= x)
) ints.push([p1,p2]);
}
let cntr = [];
if (ints.length && ints.length % 2 === 0) {
for (let int of ints) {
let [p1, p2] = int;
if (p2.x < p1.x) {
let tp = p1;
p1 = p2;
p2 = tp;
}
let minx = Math.min(p1.x, p2.x);
let maxx = Math.max(p1.x, p2.x);
let miny = Math.min(p1.y, p2.y);
let maxy = Math.max(p1.y, p2.y);
let dx = maxx - minx;
let dy = p2.y - p1.y;
let pct = (x - minx) / dx;
let ypo = p1.y + pct * dy;
cntr.push(ypo);
}
}
cntr.sort((a, b) => {
return b - a;
});
let lp, eo = 0;
for (let y of cntr) {
let p = BASE.newPoint(x, y, z);
if (eo++ % 2) {
let d = lp.distTo2D(p);
if (d >= min && d <= max) {
if (lines) {
cloud.push(lp);
cloud.push(p);
} else {
cloud.push(BASE.newPoint(
x, (lp.y + p.y) / 2, z
));
}
}
} else {
lp = p;
}
}
}
if (lines) {
return cloud;
}
let mindist = opt.mindist || step * 1.5;
function build(poly) {
let lastp = poly.last();
let minp;
let mind = Infinity;
for (let point of cloud) {
let dist = point.distTo2D(lastp);
if (dist < mindist && dist < mind) {
mind = dist;
minp = point;
}
}
if (minp) {
cloud = cloud.filter(p => p !== minp);
poly.push(minp);
return true;
}
return false;
}
// join points into polys
let polys = [];
let poly = [];
while (cloud.length) {
if (poly.length === 0) {
poly = [ cloud.shift() ];
polys.push(poly);
continue;
}
if (build(poly)) {
continue;
}
if (!poly.flip) {
poly.reverse();
poly.flip = true;
continue;
}
if (poly.length) {
poly = [];
} else {
throw "whoop there it is";
}
}
return polys
.filter(poly => poly.length > 1)
.map(poly => {
let np = BASE.newPolygon().setOpen();
for (let p of poly) {
np.push(p);
}
return np;
});
};
PRO.debur = function(dist) {
if (this.len < 2) {
return null;

View file

@ -541,6 +541,11 @@
return opts.flat ? opts.outs : polys;
}
/**
* progressive insetting that does inset + outset to debur as well
* as performing subtractive analysis between initial layer shell (ref)
* and last offset (cmp) to produce gap candidates (for thinfill)
*/
function inset(polys, dist, count, z) {
let total = count;
let layers = [];

View file

@ -2201,7 +2201,6 @@
SPACE.mouse.up((event, int) => {
if (event.button === 2 && API.view.isArrange()) {
console.log({up: event, int});
let style = UI.context.style;
style.display = 'flex';
style.left = `${event.clientX-3}px`;

View file

@ -1002,14 +1002,15 @@
KIRI.client.sync();
KIRI.client.rotate(settings);
// for each widget, slice
forAllWidgets(function(widget) {
let segtimes = {},
segNumber = 0,
errored = false,
startTime = Date.now(),
lastMsg,
camOrLaser = mode === 'CAM' || mode === 'LASER',
lastMsg;
// for each widget, slice
forAllWidgets(function(widget) {
let camOrLaser = mode === 'CAM' || mode === 'LASER',
stack = widget.stack = STACKS.create(widget.id, widget.mesh),
factor = (widget.getVertices().count / defvert);
@ -1022,7 +1023,7 @@
if (sliced) {
// update segment time
if (lastMsg) {
segtimes[`${segNumber++}_${lastMsg}`] = mark - startTime;
segtimes[`${widget.id}_${segNumber++}_${lastMsg}`] = mark - startTime;
}
API.event.emit('slice', getMode());
}
@ -1048,7 +1049,7 @@
KIRI.client.unrotate(settings, () => {
forAllWidgets(widget => {
// on done
segtimes[`${segNumber++}_draw`] = widget.render(widget.stack);
segtimes[`${widget.id}_${segNumber++}_draw`] = widget.render(widget.stack);
// rotate stack for belt beds
if (widget.rotinfo) {
widget.stack.obj.rotate(widget.rotinfo);
@ -1086,7 +1087,7 @@
if (msg && msg !== lastMsg) {
let mark = Date.now();
if (lastMsg) {
segtimes[`${segNumber++}_${lastMsg}`] = mark - startTime;
segtimes[`${widget.id}_${segNumber++}_${lastMsg}`] = mark - startTime;
}
lastMsg = msg;
startTime = mark;

View file

@ -604,10 +604,11 @@
last = null;
}
}
} else {
outputOrderClosest(poly, function(next) {
outputTraces(next, opt);
}, null);
}
// outputOrderClosest(poly, function(next) {
// outputTraces(next, opt);
// }, null);
} else {
let finishShell = poly.depth === 0 && !firstLayer;
startPoint = scope.polyPrintPath(poly, startPoint, preout, {
@ -887,20 +888,12 @@
let inner = next.innerShells() || [];
// output inner polygons
if (shellOrder === 1) outputTraces(inner);
if (shellOrder === 1) outputTraces(inner, { sort: shellOrder });
outputTraces(next.shells, { sort: shellOrder });
// sort perimeter polygon by length to go out-to-in or in-to-out
// this causes too much seeking when nesting splits into disconnected areas
// (next.shells || []).sort(function(a,b) {
// return a.perimeter() > b.perimeter() ? shellOrder : -shellOrder;
// }).forEach(function(poly, index) {
// outputTraces(poly);
// });
// output outer polygons
if (shellOrder === -1) outputTraces(inner);
if (shellOrder === -1) outputTraces(inner, { sort: shellOrder });
// output thin fill
outputFills(next.thin_fill, {near: true});

View file

@ -21,7 +21,8 @@
shell: { check: 0x0077bb, face: 0x0077bb, line: 0x0077bb, opacity: 1 },
fill: { check: 0x00bb77, face: 0x00bb77, line: 0x00bb77, opacity: 1 },
infill: { check: 0x3322bb, face: 0x3322bb, line: 0x3322bb, opacity: 1 },
support: { check: 0xaa5533, face: 0xaa5533, line: 0xaa5533, opacity: 1 }
support: { check: 0xaa5533, face: 0xaa5533, line: 0xaa5533, opacity: 1 },
gaps: { check: 0xaa3366, face: 0xaa3366, line: 0xaa3366, opacity: 1 }
},
PROTO = Object.clone(COLOR),
bwcomp = (1 / Math.cos(Math.PI/4)),
@ -463,6 +464,10 @@
.setLayer("shells", isSynth ? COLOR.support : COLOR.shell)
.addPolys(top.shells, vopt({ offset, height }));
if (top.gaps) output
.setLayer("gaps", COLOR.gaps)
.addPolys(top.gaps, vopt({ offset, height, thin: true }));
// if (isThin && debug) {
// slice.output()
// .setLayer('offset', { face: 0, line: 0x888888 })
@ -573,19 +578,19 @@
} });
if (opt.danger && opt.thin) {
top.thin_fill = [];
top.fill_sparse = [];
let layers = POLY.inset(top_poly, offsetN, count, z);
last = layers.last().mid;
top.shells = layers.map(r => r.mid).flat();
layers.map(r => r.gap).forEach((polys, i) => {
let off = offset1;
polys = POLY.offset(polys, -off * 0.8, {z, minArea: 0});
if (polys.length) {
top.thin_fill.appendAll(cullIntersections(
fillArea(polys, 45, off, [], off/4, off*4),
fillArea(polys, 135, off, [], off/4, off*4),
));
top.gaps = layers.map(r => r.gap).flat();
let off = offsetN;
let min = off * 0.9;
let max = off * 4;
for (let poly of layers.map(r => r.gap).flat()) {
let centers = poly.centers(off/2, z, min, max, {lines:false});
top.fill_sparse.appendAll(centers);
// top.thin_fill.appendAll(centers);
}
});
} else if (opt.thin) {
top.thin_fill = [];
let oso = {z, count, gaps: [], outs: [], minArea: 0.05};