improve support clipping, change gap offset from number to boolean
This commit is contained in:
parent
2c6403e865
commit
c8c789b723
5 changed files with 45 additions and 17 deletions
|
|
@ -74,10 +74,23 @@ const POLYS = {
|
||||||
union,
|
union,
|
||||||
unionFaces,
|
unionFaces,
|
||||||
xor,
|
xor,
|
||||||
|
verify
|
||||||
};
|
};
|
||||||
|
|
||||||
export { POLYS };
|
export { POLYS };
|
||||||
|
|
||||||
|
export function verify(polys) {
|
||||||
|
polys.forEach(p => {
|
||||||
|
if (!p.open && p.length < 3) console.trace('SHORT', p);
|
||||||
|
if (!p.open && p.area() < 0.001) console.trace('SMALL', p);
|
||||||
|
p.points.forEach(p => {
|
||||||
|
if (isNaN(p.x) || isNaN(p.y) ||isNaN(p.z)) {
|
||||||
|
console.trace('NaN', p);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function outer(polys) {
|
export function outer(polys) {
|
||||||
for (let p of polys) {
|
for (let p of polys) {
|
||||||
p.inner = undefined;
|
p.inner = undefined;
|
||||||
|
|
@ -136,7 +149,7 @@ export function fromClipperNode(tnode, z) {
|
||||||
export function fromClipperTree(tnode, z, tops, parent, minarea) {
|
export function fromClipperTree(tnode, z, tops, parent, minarea) {
|
||||||
let poly,
|
let poly,
|
||||||
polys = tops || [],
|
polys = tops || [],
|
||||||
min = numOrDefault(minarea, 0.1);
|
min = minarea ?? 0.1;
|
||||||
|
|
||||||
for (let child of tnode.m_Childs) {
|
for (let child of tnode.m_Childs) {
|
||||||
poly = fromClipperNode(child, z);
|
poly = fromClipperNode(child, z);
|
||||||
|
|
@ -150,7 +163,7 @@ export function fromClipperTree(tnode, z, tops, parent, minarea) {
|
||||||
polys.push(poly);
|
polys.push(poly);
|
||||||
}
|
}
|
||||||
if (child.m_Childs) {
|
if (child.m_Childs) {
|
||||||
fromClipperTree(child, z, polys, parent ? null : poly, minarea);
|
fromClipperTree(child, z, polys, parent ? null : poly, min);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -641,13 +654,15 @@ export function xor(set, z) {
|
||||||
* @param {Polygon[]} setB mask set
|
* @param {Polygon[]} setB mask set
|
||||||
* @returns {Polygon[]}
|
* @returns {Polygon[]}
|
||||||
*/
|
*/
|
||||||
export function trimTo(setA, setB) {
|
export function trimTo(setA, setB, opt = {}) {
|
||||||
// handle null/empty slices
|
// handle null/empty slices
|
||||||
if (setA === setB || setA === null || setB === null) return null;
|
if (setA === setB || setA === null || setB === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
let out = [], tmp;
|
let out = [], tmp;
|
||||||
util.doCombinations(setA, setB, {}, function(a, b) {
|
util.doCombinations(setA, setB, {}, (a, b) => {
|
||||||
if (tmp = a.mask(b)) {
|
if (tmp = a.mask(b, opt.nullEq, opt.minArea)) {
|
||||||
out.appendAll(tmp);
|
out.appendAll(tmp);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -341,7 +341,7 @@ export const conf = {
|
||||||
sliceSupportAngle: 50,
|
sliceSupportAngle: 50,
|
||||||
sliceSupportDensity: 0.1,
|
sliceSupportDensity: 0.1,
|
||||||
sliceSupportExtra: 0,
|
sliceSupportExtra: 0,
|
||||||
sliceSupportGap: 1,
|
sliceSupportGap: true,
|
||||||
sliceSupportNozzle: 0,
|
sliceSupportNozzle: 0,
|
||||||
sliceSupportOffset: 1.0,
|
sliceSupportOffset: 1.0,
|
||||||
sliceSupportOutline: true,
|
sliceSupportOutline: true,
|
||||||
|
|
|
||||||
|
|
@ -121,12 +121,12 @@ export function menu() {
|
||||||
separator: newBlank({ class:"set-sep", driven }),
|
separator: newBlank({ class:"set-sep", driven }),
|
||||||
sliceSupportAngle: newInput(LANG.sp_angl_s, {title:LANG.sp_angl_l, convert:toFloat, bound:bound(0.0,90.0)}),
|
sliceSupportAngle: newInput(LANG.sp_angl_s, {title:LANG.sp_angl_l, convert:toFloat, bound:bound(0.0,90.0)}),
|
||||||
sliceSupportDensity: newInput(LANG.sp_dens_s, {title:LANG.sp_dens_l, convert:toFloat, bound:bound(0.0,1.0)}),
|
sliceSupportDensity: newInput(LANG.sp_dens_s, {title:LANG.sp_dens_l, convert:toFloat, bound:bound(0.0,1.0)}),
|
||||||
sliceSupportGap: newInput(LANG.sp_gaps_s, {title:LANG.sp_gaps_l, convert:toInt, bound:bound(0,5)}),
|
|
||||||
sliceSupportOffset: newInput(LANG.sp_offs_s, {title:LANG.sp_offs_l, convert:toFloat, bound:bound(0.0,200.0)}),
|
sliceSupportOffset: newInput(LANG.sp_offs_s, {title:LANG.sp_offs_l, convert:toFloat, bound:bound(0.0,200.0)}),
|
||||||
sliceSupportExtra: newInput(LANG.sp_xpnd_s, {title:LANG.sp_xpnd_l, convert:toFloat, bound:bound(0.0,10.0)}),
|
sliceSupportExtra: newInput(LANG.sp_xpnd_s, {title:LANG.sp_xpnd_l, convert:toFloat, bound:bound(0.0,10.0)}),
|
||||||
// sliceSupportSpan: newInput(LANG.sp_span_s, {title:LANG.sp_span_l, convert:toFloat, bound:bound(0.0,200.0), show:() => ui.sliceSupportEnable.checked }),
|
// sliceSupportSpan: newInput(LANG.sp_span_s, {title:LANG.sp_span_l, convert:toFloat, bound:bound(0.0,200.0), show:() => ui.sliceSupportEnable.checked }),
|
||||||
separator: newBlank({ class:"set-sep", driven }),
|
separator: newBlank({ class:"set-sep", driven }),
|
||||||
sliceSupportOutline: newBoolean(LANG.sp_outl_s, onBooleanClick, {title:LANG.sp_outl_l, xshow: () => !isTree() }),
|
sliceSupportOutline: newBoolean(LANG.sp_outl_s, onBooleanClick, {title:LANG.sp_outl_l, xshow: () => !isTree() }),
|
||||||
|
sliceSupportGap: newBoolean(LANG.sp_gaps_s, onBooleanClick, {title:LANG.sp_gaps_l }),
|
||||||
sliceSupportTree: newBoolean(LANG.sp_tree_s, onBooleanClick, {title:LANG.sp_tree_l }),
|
sliceSupportTree: newBoolean(LANG.sp_tree_s, onBooleanClick, {title:LANG.sp_tree_l }),
|
||||||
separator: newBlank({ class:"set-sep", driven, show:manualSupport }),
|
separator: newBlank({ class:"set-sep", driven, show:manualSupport }),
|
||||||
sliceSupportManual: newRow([
|
sliceSupportManual: newRow([
|
||||||
|
|
|
||||||
|
|
@ -540,6 +540,9 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
||||||
if (manual && paint?.length) {
|
if (manual && paint?.length) {
|
||||||
let hpi = Math.PI/2;
|
let hpi = Math.PI/2;
|
||||||
for (let slice of stack) {
|
for (let slice of stack) {
|
||||||
|
if (!slice.up) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let polys = [];
|
let polys = [];
|
||||||
for (let rec of paint) {
|
for (let rec of paint) {
|
||||||
let { point, radius } = rec;
|
let { point, radius } = rec;
|
||||||
|
|
@ -550,13 +553,21 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
||||||
polys.push(newPolygon().centerCircle(point, radius, 10));
|
polys.push(newPolygon().centerCircle(point, radius, 10));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
slice.shadow = POLY.union(polys, 0, true);
|
// trim polys to part overhangs
|
||||||
|
let top = slice.up.topPolys();
|
||||||
|
let bot = slice.topPolys();
|
||||||
|
let bridge = [];
|
||||||
|
let propose = POLY.setZ(POLY.union(polys, 0, true), slice.z);
|
||||||
|
POLY.subtract(top, bot, bridge, undefined, slice.z, 0, { wasm: true });
|
||||||
|
propose = POLY.trimTo(propose, bridge, { minArea: 0 });
|
||||||
|
slice.shadow = propose;
|
||||||
|
// if (devel) slice.output().setLayer("over", 0x8844aa).addPolys(bridge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. accumulate / union shadow coverage top down
|
// 1. accumulate / union shadow coverage top down
|
||||||
// 2. trim to area outside slice.clips
|
// 2. trim to area outside slice.clips
|
||||||
let minArea = lineWidth;
|
let minArea = lineWidth * lineWidth;
|
||||||
let shadowSum;
|
let shadowSum;
|
||||||
let length = stack.length;
|
let length = stack.length;
|
||||||
let count = 0;
|
let count = 0;
|
||||||
|
|
@ -569,7 +580,7 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
||||||
// perform accumulation top down
|
// perform accumulation top down
|
||||||
for (let slice of stack.reverse()) {
|
for (let slice of stack.reverse()) {
|
||||||
let shadow = slice.shadow ?? [];
|
let shadow = slice.shadow ?? [];
|
||||||
if (devel) slice.output().setLayer("shadow", 0xff0000).addPolys(shadow.clone(true));
|
if (devel) slice.output().setLayer("shadow", 0xff0000).addPolys(shadow);
|
||||||
if (process.sliceSupportExtra) {
|
if (process.sliceSupportExtra) {
|
||||||
shadow = POLY.offset(shadow, process.sliceSupportExtra);
|
shadow = POLY.offset(shadow, process.sliceSupportExtra);
|
||||||
}
|
}
|
||||||
|
|
@ -577,10 +588,10 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
||||||
if (shadowSum) {
|
if (shadowSum) {
|
||||||
shadow = POLY.union([...shadow, ...shadowSum], minArea, true);
|
shadow = POLY.union([...shadow, ...shadowSum], minArea, true);
|
||||||
}
|
}
|
||||||
// subtract slice.clips areas (widget boundaries) from shadow projection
|
// subtract slice top areas (widget boundaries) from shadow projection
|
||||||
if (true) {
|
if (true) {
|
||||||
let rem = [];
|
let rem = [];
|
||||||
let clips = [ slice.clips ].filter(v => v).flat();
|
let clips = [ slice.topPolys() ].filter(v => v).flat();
|
||||||
clips = POLY.union(clips, minArea, true);
|
clips = POLY.union(clips, minArea, true);
|
||||||
POLY.subtract(shadow, clips, rem, null, slice.z, minArea, { wasm: false });
|
POLY.subtract(shadow, clips, rem, null, slice.z, minArea, { wasm: false });
|
||||||
shadow = rem;
|
shadow = rem;
|
||||||
|
|
@ -608,11 +619,13 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
||||||
trackupdate((++count/length), div[1].lo, div[1].hi, "support");
|
trackupdate((++count/length), div[1].lo, div[1].hi, "support");
|
||||||
}
|
}
|
||||||
|
|
||||||
// clip shadow to layers above/below clip areas (for part separation)
|
// trim using support part offset value
|
||||||
|
let gaps = process.sliceSupportGap;
|
||||||
for (let slice of stack.reverse()) {
|
for (let slice of stack.reverse()) {
|
||||||
let clips = [
|
let clips = [
|
||||||
slice.up?.clips,
|
slice.clips,
|
||||||
slice.down?.clips
|
gaps ? slice.up?.clips : undefined,
|
||||||
|
gaps ? slice.down?.clips : undefined
|
||||||
].filter(v => v).flat();
|
].filter(v => v).flat();
|
||||||
if (clips.length) {
|
if (clips.length) {
|
||||||
let rem = [];
|
let rem = [];
|
||||||
|
|
|
||||||
|
|
@ -472,7 +472,7 @@ self.lang['en-us'] = {
|
||||||
sp_offs_s: "part offset",
|
sp_offs_s: "part offset",
|
||||||
sp_offs_l: ["offset from part","in millimeters"],
|
sp_offs_l: ["offset from part","in millimeters"],
|
||||||
sp_gaps_s: "layer gap",
|
sp_gaps_s: "layer gap",
|
||||||
sp_gaps_l: ["number of layers","offset from part"],
|
sp_gaps_l: ["add a layer gap between support and part"],
|
||||||
sp_span_s: "max span",
|
sp_span_s: "max span",
|
||||||
sp_span_l: ["unsupported span that causes","a new support to be generated","in millimeters"],
|
sp_span_l: ["unsupported span that causes","a new support to be generated","in millimeters"],
|
||||||
sp_angl_s: "angle",
|
sp_angl_s: "angle",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue