add new experimental thin fill
This commit is contained in:
parent
2a345c8471
commit
bc33c71f34
8 changed files with 216 additions and 37 deletions
|
|
@ -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
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 = [];
|
||||
|
|
|
|||
|
|
@ -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`;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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});
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
Loading…
Reference in a new issue