annotate thin shells for output ordering
This commit is contained in:
parent
e2c5fc4a98
commit
07213ddc79
5 changed files with 62 additions and 19 deletions
|
|
@ -1104,6 +1104,14 @@ export class Polygon {
|
||||||
return this.first().isEqual(this.last());
|
return this.first().isEqual(this.last());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
closeIf(dist = 1) {
|
||||||
|
if (this.first().distTo2D(this.last()) <= dist) {
|
||||||
|
return this.setClosed();
|
||||||
|
} else {
|
||||||
|
return this.setOpen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fixClosed() {
|
fixClosed() {
|
||||||
if (this.appearsClosed()) {
|
if (this.appearsClosed()) {
|
||||||
this.points.pop();
|
this.points.pop();
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,7 @@ class Slice {
|
||||||
let top = new Top(data.poly);
|
let top = new Top(data.poly);
|
||||||
top.thin_fill = data.thin_fill?.map(p => newPoint(p.x,p.y,p.z));
|
top.thin_fill = data.thin_fill?.map(p => newPoint(p.x,p.y,p.z));
|
||||||
top.thin_wall = data.thin_wall;
|
top.thin_wall = data.thin_wall;
|
||||||
|
top.thin_sort = data.thin_sort;
|
||||||
top.fill_lines = data.fill_lines;
|
top.fill_lines = data.fill_lines;
|
||||||
top.fill_sparse = data.fill_sparse;
|
top.fill_sparse = data.fill_sparse;
|
||||||
top.fill_off = data.fill_off;
|
top.fill_off = data.fill_off;
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,7 @@ function thin_type_3(params) {
|
||||||
let debugExtrusion = false;
|
let debugExtrusion = false;
|
||||||
|
|
||||||
let shells = top.shells; // only used for debug
|
let shells = top.shells; // only used for debug
|
||||||
let trace = top.thin_wall = [];
|
let traces = top.thin_wall = [];
|
||||||
|
|
||||||
let midR = offsetN * 0.5; // nominal extrusion width
|
let midR = offsetN * 0.5; // nominal extrusion width
|
||||||
let minR = midR * 0.75; // smallest interior fill or single wall width
|
let minR = midR * 0.75; // smallest interior fill or single wall width
|
||||||
|
|
@ -199,11 +199,11 @@ function thin_type_3(params) {
|
||||||
i === 0 ? midR : midR * 1.25,
|
i === 0 ? midR : midR * 1.25,
|
||||||
i === 0 ? maxR : maxF,
|
i === 0 ? maxR : maxF,
|
||||||
{
|
{
|
||||||
shell: 0,
|
shell: i + 1,
|
||||||
lines,
|
lines,
|
||||||
polys,
|
polys,
|
||||||
remain,
|
remain,
|
||||||
trace,
|
traces,
|
||||||
brute: false,
|
brute: false,
|
||||||
showMedialAxis: false,
|
showMedialAxis: false,
|
||||||
showChainIntersect: false
|
showChainIntersect: false
|
||||||
|
|
@ -228,7 +228,12 @@ function thin_type_3(params) {
|
||||||
if (lines.length) top.thin_fill = lines;
|
if (lines.length) top.thin_fill = lines;
|
||||||
if (polys.length) shells.push(...polys);
|
if (polys.length) shells.push(...polys);
|
||||||
|
|
||||||
return { trace, last: remain };
|
// create shell depth annotation that will survive serialization
|
||||||
|
top.thin_sort = traces.map(a => a.shell);
|
||||||
|
|
||||||
|
console.log({ this: (self.kiri_minion?.name ?? self.kiri_worker), traces });
|
||||||
|
|
||||||
|
return { traces, last: remain };
|
||||||
}
|
}
|
||||||
|
|
||||||
// trace a single extrusion line around the inside of the noodle poly
|
// trace a single extrusion line around the inside of the noodle poly
|
||||||
|
|
@ -243,7 +248,7 @@ function trace_noodle(noodle, noodleWidth, minR, midR, maxR, opt = {}) {
|
||||||
lines = [],
|
lines = [],
|
||||||
polys = [],
|
polys = [],
|
||||||
remain = [],
|
remain = [],
|
||||||
trace = [],
|
traces = [],
|
||||||
shell = 0
|
shell = 0
|
||||||
} = opt;
|
} = opt;
|
||||||
|
|
||||||
|
|
@ -447,7 +452,9 @@ function trace_noodle(noodle, noodleWidth, minR, midR, maxR, opt = {}) {
|
||||||
if (poly.parent) {
|
if (poly.parent) {
|
||||||
inner.push(nupoly);
|
inner.push(nupoly);
|
||||||
}
|
}
|
||||||
let fpo;
|
let ltpo;
|
||||||
|
let trace = [];
|
||||||
|
trace.shell = sno;
|
||||||
poly.segment(minR).forEachSegment((p1, p2) => {
|
poly.segment(minR).forEachSegment((p1, p2) => {
|
||||||
let np1 = { x:(p1.x+p2.x)/2, y:(p1.y+p2.y)/2 };
|
let np1 = { x:(p1.x+p2.x)/2, y:(p1.y+p2.y)/2 };
|
||||||
let len = pointDist(p1, p2);
|
let len = pointDist(p1, p2);
|
||||||
|
|
@ -489,7 +496,7 @@ function trace_noodle(noodle, noodleWidth, minR, midR, maxR, opt = {}) {
|
||||||
// let rad_step = ((pop[0] * sstep) | 0) / sstep;
|
// let rad_step = ((pop[0] * sstep) | 0) / sstep;
|
||||||
// for single wall place it exactly on medial axis
|
// for single wall place it exactly on medial axis
|
||||||
nupoly.push(new Point(min.x, min.y));
|
nupoly.push(new Point(min.x, min.y));
|
||||||
trace.push(op = { x: min.x, y: min.y, r: mr, sno })
|
trace.push(op = { x: min.x, y: min.y, r: mr })
|
||||||
} else {
|
} else {
|
||||||
// radius rounded to nearest step
|
// radius rounded to nearest step
|
||||||
let rad_step = ((pop[0] * sstep) | 0) / sstep;
|
let rad_step = ((pop[0] * sstep) | 0) / sstep;
|
||||||
|
|
@ -499,8 +506,7 @@ function trace_noodle(noodle, noodleWidth, minR, midR, maxR, opt = {}) {
|
||||||
trace.push(op = {
|
trace.push(op = {
|
||||||
x: np1.x + dy * off,
|
x: np1.x + dy * off,
|
||||||
y: np1.y - dx * off,
|
y: np1.y - dx * off,
|
||||||
r: rad_step,
|
r: rad_step
|
||||||
sno
|
|
||||||
})
|
})
|
||||||
// trace inset by full diameter
|
// trace inset by full diameter
|
||||||
nupoly.push(new Point(np1.x + dy * off * 2, np1.y - dx * off * 2));
|
nupoly.push(new Point(np1.x + dy * off * 2, np1.y - dx * off * 2));
|
||||||
|
|
@ -508,13 +514,29 @@ function trace_noodle(noodle, noodleWidth, minR, midR, maxR, opt = {}) {
|
||||||
if (odd && !mp1.claimed) {
|
if (odd && !mp1.claimed) {
|
||||||
mp1.claimed = true;
|
mp1.claimed = true;
|
||||||
}
|
}
|
||||||
// store first trace out for this poly to repeat at the end
|
// detect trace jump and start new trace
|
||||||
fpo = fpo ?? trace.peek();
|
if (ltpo && pointDist(ltpo, trace.peek()) > maxR) {
|
||||||
|
// start new trace removing jump point
|
||||||
|
// and adding that to the new trace
|
||||||
|
traces.push(trace);
|
||||||
|
let nutrace = [ trace.pop() ];
|
||||||
|
nutrace.shell = sno;
|
||||||
|
// close last trace if endpoints near enough
|
||||||
|
if (pointDist(ltpo, trace[0] <= maxR)) {
|
||||||
|
trace.push(trace[0]);
|
||||||
|
}
|
||||||
|
trace = nutrace;
|
||||||
|
}
|
||||||
|
// update last trace point out
|
||||||
|
ltpo = trace.peek();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// repeat first point of trace (if close enough to be closed)
|
// repeat first point of trace (if close enough to be closed)
|
||||||
if (fpo && pointDist(fpo, trace.peek()) <= maxR) {
|
if (trace[0] && pointDist(trace[0], trace.peek()) <= maxR) {
|
||||||
trace.push(fpo);
|
trace.push(trace[0]);
|
||||||
|
}
|
||||||
|
if (trace.length) {
|
||||||
|
traces.push(trace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -534,10 +556,11 @@ function trace_noodle(noodle, noodleWidth, minR, midR, maxR, opt = {}) {
|
||||||
return p.clean().simplify();
|
return p.clean().simplify();
|
||||||
}).flat()
|
}).flat()
|
||||||
).filter(p => p.area() >= minArea);
|
).filter(p => p.area() >= minArea);
|
||||||
|
|
||||||
remain.push(...ret);
|
remain.push(...ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { lines, polys, remain, trace };
|
return { lines, polys, remain, traces };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1089,9 +1089,14 @@ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function outputAdaptiveWalls(thin, opt = {}) {
|
function outputAdaptiveWalls(thin, sort, opt = {}) {
|
||||||
|
// restore thin shell order annotation and sort on it
|
||||||
|
thin.forEach((a,i) => a.shell = sort[i]);
|
||||||
|
thin.sort((a,b) => (a.shell - b.shell) * shellOrder);
|
||||||
|
// perform nearest poly to poly algorithm on shells
|
||||||
let np;
|
let np;
|
||||||
for (let pt of thin) {
|
for (let trace of thin)
|
||||||
|
for (let pt of trace) {
|
||||||
let { lastPoint, lastEmit } = print;
|
let { lastPoint, lastEmit } = print;
|
||||||
let { x, y, r } = pt;
|
let { x, y, r } = pt;
|
||||||
np = new Point(x, y, z);
|
np = new Point(x, y, z);
|
||||||
|
|
@ -1459,7 +1464,7 @@ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) {
|
||||||
if (top.traces) outputTraces(top.traces);
|
if (top.traces) outputTraces(top.traces);
|
||||||
|
|
||||||
// thin wall v3
|
// thin wall v3
|
||||||
if (top.thin_wall) outputAdaptiveWalls(top.thin_wall);
|
if (top.thin_wall) outputAdaptiveWalls(top.thin_wall, top.thin_sort);
|
||||||
|
|
||||||
// innermost shells
|
// innermost shells
|
||||||
let inner = next.innerShells() || [];
|
let inner = next.innerShells() || [];
|
||||||
|
|
|
||||||
|
|
@ -1003,11 +1003,17 @@ function doRender(slice, isSynth, params, opt = {}) {
|
||||||
|
|
||||||
if (isThin && top.thin_wall?.length) output
|
if (isThin && top.thin_wall?.length) output
|
||||||
.setLayer("walls", Color.thin)
|
.setLayer("walls", Color.thin)
|
||||||
.addPolys(top.thin_wall.map(p => newPolygon().centerCircle(p, p.r, 12).setZ(slice.z)), vopt({ offset, height }));
|
.addPolys(top.thin_wall.map(a => a.map(p => newPolygon().centerCircle(p, p.r, 12).setZ(slice.z))).flat(), vopt({ offset, height }));
|
||||||
|
|
||||||
if (!isThin && top.thin_wall?.length) output
|
if (!isThin && top.thin_wall?.length) output
|
||||||
.setLayer("walls", Color.thin)
|
.setLayer("walls", Color.thin)
|
||||||
.addPolys(top.thin_wall.map(p => newPolygon().centerCircle(p, p.r, 3).setZ(slice.z)), vopt({ offset, height }));
|
.addPolys(top.thin_wall.map(a =>
|
||||||
|
a.length === 1 ?
|
||||||
|
newPolygon().centerCircle(a[0], a[0].r, 6) :
|
||||||
|
newPolygon(a.map(p => newPoint(p.x, p.y)))
|
||||||
|
.setZ(slice.z)
|
||||||
|
.closeIf(height)
|
||||||
|
), vopt({ offset, height }));
|
||||||
|
|
||||||
if (top.fill_lines?.length) output
|
if (top.fill_lines?.length) output
|
||||||
.setLayer("solid fill", isSynth ? Color.support : Color.fill)
|
.setLayer("solid fill", isSynth ? Color.support : Color.fill)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue