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,
|
"origin_center": false,
|
||||||
"extrude_abs": true,
|
"extrude_abs": true,
|
||||||
"bed_belt": true,
|
"bed_belt": true,
|
||||||
"bed_width": 215,
|
"bed_width": 220,
|
||||||
"bed_depth": 300,
|
"bed_depth": 300,
|
||||||
"build_height": 170
|
"build_height": 170
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
function time() { return Date.now() }
|
function time() { return Date.now() }
|
||||||
|
|
||||||
function lerp(from, to, maxInc) {
|
function lerp(from, to, maxInc, incFrom) {
|
||||||
let dir = Math.sign(to - from);
|
let dir = Math.sign(to - from);
|
||||||
let delta = Math.abs(to - from);
|
let delta = Math.abs(to - from);
|
||||||
let steps = Math.floor(delta / maxInc);
|
let steps = Math.floor(delta / maxInc);
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
steps++;
|
steps++;
|
||||||
per = delta / steps;
|
per = delta / steps;
|
||||||
}
|
}
|
||||||
let out = [];
|
let out = incFrom ? [from] : [];
|
||||||
while (steps-- > 0) {
|
while (steps-- > 0) {
|
||||||
from += per * dir;
|
from += per * dir;
|
||||||
out.push(from);
|
out.push(from);
|
||||||
|
|
|
||||||
|
|
@ -260,6 +260,182 @@
|
||||||
return Math.abs(diff);
|
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) {
|
PRO.debur = function(dist) {
|
||||||
if (this.len < 2) {
|
if (this.len < 2) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -541,6 +541,11 @@
|
||||||
return opts.flat ? opts.outs : polys;
|
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) {
|
function inset(polys, dist, count, z) {
|
||||||
let total = count;
|
let total = count;
|
||||||
let layers = [];
|
let layers = [];
|
||||||
|
|
|
||||||
|
|
@ -2201,7 +2201,6 @@
|
||||||
|
|
||||||
SPACE.mouse.up((event, int) => {
|
SPACE.mouse.up((event, int) => {
|
||||||
if (event.button === 2 && API.view.isArrange()) {
|
if (event.button === 2 && API.view.isArrange()) {
|
||||||
console.log({up: event, int});
|
|
||||||
let style = UI.context.style;
|
let style = UI.context.style;
|
||||||
style.display = 'flex';
|
style.display = 'flex';
|
||||||
style.left = `${event.clientX-3}px`;
|
style.left = `${event.clientX-3}px`;
|
||||||
|
|
|
||||||
|
|
@ -1002,14 +1002,15 @@
|
||||||
KIRI.client.sync();
|
KIRI.client.sync();
|
||||||
KIRI.client.rotate(settings);
|
KIRI.client.rotate(settings);
|
||||||
|
|
||||||
|
let segtimes = {},
|
||||||
|
segNumber = 0,
|
||||||
|
errored = false,
|
||||||
|
startTime = Date.now(),
|
||||||
|
lastMsg;
|
||||||
|
|
||||||
// for each widget, slice
|
// for each widget, slice
|
||||||
forAllWidgets(function(widget) {
|
forAllWidgets(function(widget) {
|
||||||
let segtimes = {},
|
let camOrLaser = mode === 'CAM' || mode === 'LASER',
|
||||||
segNumber = 0,
|
|
||||||
errored = false,
|
|
||||||
startTime = Date.now(),
|
|
||||||
lastMsg,
|
|
||||||
camOrLaser = mode === 'CAM' || mode === 'LASER',
|
|
||||||
stack = widget.stack = STACKS.create(widget.id, widget.mesh),
|
stack = widget.stack = STACKS.create(widget.id, widget.mesh),
|
||||||
factor = (widget.getVertices().count / defvert);
|
factor = (widget.getVertices().count / defvert);
|
||||||
|
|
||||||
|
|
@ -1022,7 +1023,7 @@
|
||||||
if (sliced) {
|
if (sliced) {
|
||||||
// update segment time
|
// update segment time
|
||||||
if (lastMsg) {
|
if (lastMsg) {
|
||||||
segtimes[`${segNumber++}_${lastMsg}`] = mark - startTime;
|
segtimes[`${widget.id}_${segNumber++}_${lastMsg}`] = mark - startTime;
|
||||||
}
|
}
|
||||||
API.event.emit('slice', getMode());
|
API.event.emit('slice', getMode());
|
||||||
}
|
}
|
||||||
|
|
@ -1048,7 +1049,7 @@
|
||||||
KIRI.client.unrotate(settings, () => {
|
KIRI.client.unrotate(settings, () => {
|
||||||
forAllWidgets(widget => {
|
forAllWidgets(widget => {
|
||||||
// on done
|
// on done
|
||||||
segtimes[`${segNumber++}_draw`] = widget.render(widget.stack);
|
segtimes[`${widget.id}_${segNumber++}_draw`] = widget.render(widget.stack);
|
||||||
// rotate stack for belt beds
|
// rotate stack for belt beds
|
||||||
if (widget.rotinfo) {
|
if (widget.rotinfo) {
|
||||||
widget.stack.obj.rotate(widget.rotinfo);
|
widget.stack.obj.rotate(widget.rotinfo);
|
||||||
|
|
@ -1086,7 +1087,7 @@
|
||||||
if (msg && msg !== lastMsg) {
|
if (msg && msg !== lastMsg) {
|
||||||
let mark = Date.now();
|
let mark = Date.now();
|
||||||
if (lastMsg) {
|
if (lastMsg) {
|
||||||
segtimes[`${segNumber++}_${lastMsg}`] = mark - startTime;
|
segtimes[`${widget.id}_${segNumber++}_${lastMsg}`] = mark - startTime;
|
||||||
}
|
}
|
||||||
lastMsg = msg;
|
lastMsg = msg;
|
||||||
startTime = mark;
|
startTime = mark;
|
||||||
|
|
|
||||||
|
|
@ -604,10 +604,11 @@
|
||||||
last = null;
|
last = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
outputOrderClosest(poly, function(next) {
|
||||||
|
outputTraces(next, opt);
|
||||||
|
}, null);
|
||||||
}
|
}
|
||||||
// outputOrderClosest(poly, function(next) {
|
|
||||||
// outputTraces(next, opt);
|
|
||||||
// }, null);
|
|
||||||
} else {
|
} else {
|
||||||
let finishShell = poly.depth === 0 && !firstLayer;
|
let finishShell = poly.depth === 0 && !firstLayer;
|
||||||
startPoint = scope.polyPrintPath(poly, startPoint, preout, {
|
startPoint = scope.polyPrintPath(poly, startPoint, preout, {
|
||||||
|
|
@ -887,20 +888,12 @@
|
||||||
let inner = next.innerShells() || [];
|
let inner = next.innerShells() || [];
|
||||||
|
|
||||||
// output inner polygons
|
// output inner polygons
|
||||||
if (shellOrder === 1) outputTraces(inner);
|
if (shellOrder === 1) outputTraces(inner, { sort: shellOrder });
|
||||||
|
|
||||||
outputTraces(next.shells, { 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
|
// output outer polygons
|
||||||
if (shellOrder === -1) outputTraces(inner);
|
if (shellOrder === -1) outputTraces(inner, { sort: shellOrder });
|
||||||
|
|
||||||
// output thin fill
|
// output thin fill
|
||||||
outputFills(next.thin_fill, {near: true});
|
outputFills(next.thin_fill, {near: true});
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,8 @@
|
||||||
shell: { check: 0x0077bb, face: 0x0077bb, line: 0x0077bb, opacity: 1 },
|
shell: { check: 0x0077bb, face: 0x0077bb, line: 0x0077bb, opacity: 1 },
|
||||||
fill: { check: 0x00bb77, face: 0x00bb77, line: 0x00bb77, opacity: 1 },
|
fill: { check: 0x00bb77, face: 0x00bb77, line: 0x00bb77, opacity: 1 },
|
||||||
infill: { check: 0x3322bb, face: 0x3322bb, line: 0x3322bb, 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),
|
PROTO = Object.clone(COLOR),
|
||||||
bwcomp = (1 / Math.cos(Math.PI/4)),
|
bwcomp = (1 / Math.cos(Math.PI/4)),
|
||||||
|
|
@ -463,6 +464,10 @@
|
||||||
.setLayer("shells", isSynth ? COLOR.support : COLOR.shell)
|
.setLayer("shells", isSynth ? COLOR.support : COLOR.shell)
|
||||||
.addPolys(top.shells, vopt({ offset, height }));
|
.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) {
|
// if (isThin && debug) {
|
||||||
// slice.output()
|
// slice.output()
|
||||||
// .setLayer('offset', { face: 0, line: 0x888888 })
|
// .setLayer('offset', { face: 0, line: 0x888888 })
|
||||||
|
|
@ -573,19 +578,19 @@
|
||||||
} });
|
} });
|
||||||
if (opt.danger && opt.thin) {
|
if (opt.danger && opt.thin) {
|
||||||
top.thin_fill = [];
|
top.thin_fill = [];
|
||||||
|
top.fill_sparse = [];
|
||||||
let layers = POLY.inset(top_poly, offsetN, count, z);
|
let layers = POLY.inset(top_poly, offsetN, count, z);
|
||||||
last = layers.last().mid;
|
last = layers.last().mid;
|
||||||
top.shells = layers.map(r => r.mid).flat();
|
top.shells = layers.map(r => r.mid).flat();
|
||||||
layers.map(r => r.gap).forEach((polys, i) => {
|
top.gaps = layers.map(r => r.gap).flat();
|
||||||
let off = offset1;
|
let off = offsetN;
|
||||||
polys = POLY.offset(polys, -off * 0.8, {z, minArea: 0});
|
let min = off * 0.9;
|
||||||
if (polys.length) {
|
let max = off * 4;
|
||||||
top.thin_fill.appendAll(cullIntersections(
|
for (let poly of layers.map(r => r.gap).flat()) {
|
||||||
fillArea(polys, 45, off, [], off/4, off*4),
|
let centers = poly.centers(off/2, z, min, max, {lines:false});
|
||||||
fillArea(polys, 135, off, [], off/4, off*4),
|
top.fill_sparse.appendAll(centers);
|
||||||
));
|
// top.thin_fill.appendAll(centers);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
} else if (opt.thin) {
|
} else if (opt.thin) {
|
||||||
top.thin_fill = [];
|
top.thin_fill = [];
|
||||||
let oso = {z, count, gaps: [], outs: [], minArea: 0.05};
|
let oso = {z, count, gaps: [], outs: [], minArea: 0.05};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue