allow FDM mixing of automatic and manual / detected supports. add outline toggling to automatic supports

This commit is contained in:
Stewart Allen 2022-10-13 11:16:44 -04:00
commit fc6973ecf9
5 changed files with 68 additions and 69 deletions

View file

@ -5,6 +5,7 @@ Full docs @ https://docs.grid.space/projects/kiri-moto
# Release 3.6
* allow FDM mixing of automatic and manual / detected supports
* improve CAM animation speeds using shared array buffers
* improve CAM render quality using solids instead of lines
* add CAM leveling part offset parameters for XY and Z

View file

@ -130,23 +130,6 @@ FDM.init = function(kiri, api) {
}
}
api.event.on("boolean.click", func.updateSupportButtons = () => {
if (!isFdmMode) {
return;
}
for (let btn of [
ui.ssaGen,
ui.ssmAdd,
ui.ssmDun,
ui.ssmClr
]) {
btn.disabled = ui.sliceSupportEnable.checked;
}
if (ui.sliceSupportEnable.checked) {
func.sclear();
}
});
api.event.on("function.animate", (mode) => {
if (!isFdmMode) {
return;
@ -205,7 +188,6 @@ FDM.init = function(kiri, api) {
});
api.event.on("settings.saved", (settings) => {
updateRanges(settings.process.ranges);
func.updateSupportButtons();
// let ranges = settings.process.ranges;
// ui.rangeGroup.style.display = isFdmMode && ranges && ranges.length ? 'flex' : 'none';
});

View file

@ -35,7 +35,7 @@ FDM.prepare = function(widgets, settings, update) {
widgets = widgets.filter(w => !w.track.ignore && !w.meta.disabled);
let { device, process, controller, bounds, mode } = settings,
{ sliceHeight, firstSliceHeight, firstLayerRate } = process,
{ sliceHeight, firstSliceHeight, firstLayerRate, sliceSupportOutline } = process,
{ outputSeekrate, outputDraftShield, outputPurgeTower } = process,
{ bedWidth, bedDepth, filamentSource } = device,
{ lineType, danger } = controller,
@ -1358,7 +1358,9 @@ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) {
print.setType('support');
// support polygon
next.setZ(z);
if (sliceSupportOutline !== false) {
outputTraces([next].appendAll(next.inner || []));
}
if (next.fill) {
next.fill.forEach(p => { p.z = z });
outputFills(next.fill, {fast: true});

View file

@ -127,7 +127,8 @@ FDM.slice = function(settings, widget, onupdate, ondone) {
// allow overriding support fill auto angle algorithm
// also causes support fill to be aligned on start boundaries
// best with angles that are a multiple of 90 degrees
if (process.sliceSupportFill !== undefined) {
if (process.sliceSupportFill >= 0) {
// yes, an ugly hack to allow it to pass through old code paths
process.sliceSupportFill += 1000;
}
@ -414,8 +415,15 @@ FDM.slice = function(settings, widget, onupdate, ondone) {
if (Math.abs(Math.abs(pslice.z - slice.z) - gap) > 0.1) {
continue;
}
let clipto = pslice.clips;
if (pslice.supportOutline) {
// merge support outlines into slice clips which
// should only happen when automatic and manual
// supports are used together
clipto.appendAll(pslice.supportOutline);
}
let ntops = [];
POLY.subtract(tops, pslice.clips, ntops, null, slice.z, 0);
POLY.subtract(tops, clipto, ntops, null, slice.z, 0);
tops = ntops;
}
// trim to group's shadow if not in belt mode
@ -724,23 +732,18 @@ FDM.slice = function(settings, widget, onupdate, ondone) {
let density = params.sliceSupportDensity;
if (density)
for (let top of slice.tops) {
if (!outline) {
let offset = top.shells;
fillSupportPolys({
promises, polys: offset, lineWidth, density, z: slice.z, isBelt,
angle: process.sliceSupportFill
});
resolve.push({top, offset});
} else {
let offset = [];
if (!outline) {
POLY.expand(top.shells || [], lineWidth, slice.z, offset);
} else {
POLY.expand(top.shells || [], -lineWidth/4, slice.z, offset);
}
fillSupportPolys({
promises, polys: offset, lineWidth, density, z: slice.z, isBelt,
angle: process.sliceSupportFill
});
resolve.push({top, offset});
}
}
}, "infill");
if (promises) {
await tracker(promises, (i, t) => {
@ -748,35 +751,11 @@ FDM.slice = function(settings, widget, onupdate, ondone) {
});
}
for (let rec of resolve) {
let spacing = lineWidth * (1 / supportDensity);
let lines = rec.top.fill_lines = rec.offset.map(o => o.fill).flat().filter(v => v);
// if copying simply's support type, eliminate shells
// and zig/zag lines connectd by shell segments
// if copying simply's support type, eliminate shells and zig/zag fill lines
if (!outline) {
let newlines = [];
let op2;
let eo = 0;
let idx = 1;
for (let i=0; i<lines.length; i += 2) {
let p1 = lines[i];
let p2 = lines[i+1];
p1.index = idx;
p2.index = idx++;
if (eo++ % 2 === 1) {
let t = p1;
p1 = p2;
p2 = t;
}
if (op2) {
let op1 = p1.clone();
op1.index = op2.index;
newlines.push(op2);
newlines.push(op1);
}
newlines.push(p1);
newlines.push(p2);
op2 = p2.clone();
op2.index = idx++;
}
let newlines = connect_lines(lines, spacing * 2);
rec.top.fill_lines = newlines;
rec.top.shells = [];
}
@ -801,7 +780,8 @@ FDM.slice = function(settings, widget, onupdate, ondone) {
doSupportFill({
promises, slice, lineWidth, density: supportDensity,
minArea: process.sliceSupportArea, isBelt,
angle: process.sliceSupportFill
angle: process.sliceSupportFill,
outline: process.sliceSupportOutline !== false
});
}, "support");
if (promises) {
@ -832,6 +812,35 @@ FDM.slice = function(settings, widget, onupdate, ondone) {
}
function connect_lines(lines, maxd = Infinity) {
const newlines = [];
let op2;
let eo = 0;
let idx = 1;
for (let i=0; i<lines.length; i += 2) {
let p1 = lines[i];
let p2 = lines[i+1];
p1.index = idx;
p2.index = idx++;
if (eo++ % 2 === 1) {
let t = p1;
p1 = p2;
p2 = t;
}
if (op2 && p1.distTo2D(op2) <= maxd) {
let op1 = p1.clone();
op1.index = op2.index;
newlines.push(op2);
newlines.push(op1);
}
newlines.push(p1);
newlines.push(p2);
op2 = p2.clone();
op2.index = idx++;
}
return newlines;
}
function bound(v,min,max) {
return Math.max(min,Math.min(max,v));
}
@ -847,7 +856,7 @@ function doRender(slice, isSynth, params, devel) {
.addPolys(top.poly);
output
.setLayer("shells", isSynth ? COLOR.support : COLOR.shell)
.setLayer(isSynth ? "support" : "shells", isSynth ? COLOR.support : COLOR.shell)
.addPolys(top.shells || [], vopt({ offset, height, clean: true }));
output
@ -893,7 +902,7 @@ function doRender(slice, isSynth, params, devel) {
.addAreas(slice.flats);
}
if (slice.supports) output
if (slice.supports && params.sliceSupportOutline) output
.setLayer("support", COLOR.support)
.addPolys(slice.supports, vopt({ offset, height }));
@ -902,6 +911,7 @@ function doRender(slice, isSynth, params, devel) {
.setLayer("support", COLOR.support)
.addLines(poly.fill, vopt({ offset, height }));
});
if (slice.xray) {
const color = [ 0xff0000, 0x00aa00, 0x0000ff, 0xaaaa00, 0xff00ff, 0x0 ];
if (slice.lines) {
@ -1517,7 +1527,7 @@ async function doSupport(slice, proc, shadow, opt = {}) {
}
function doSupportFill(args) {
const { promises, slice, lineWidth, density, minArea, isBelt, angle } = args;
const { promises, slice, lineWidth, density, minArea, isBelt, angle, outline } = args;
let supports = slice.supports,
nsB = [],
nsC = [],
@ -1540,16 +1550,17 @@ function doSupportFill(args) {
if (supports) {
fillSupportPolys({
promises, polys: supports, lineWidth, density, z: slice.z, isBelt, angle
promises, polys: supports, lineWidth, density, z: slice.z, isBelt, angle, outline
});
}
// re-assign new supports back to slice
slice.supportOutline = supports;
slice.supports = supports;
};
function fillSupportPolys(args) {
const { promises, polys, lineWidth, density, z, isBelt, angle } = args;
const { promises, polys, lineWidth, density, z, isBelt, angle, outline } = args;
// calculate fill density
let spacing = lineWidth * (1 / density);
polys.forEach(function (poly) {
@ -1560,6 +1571,9 @@ function fillSupportPolys(args) {
// do the fill
if (inset && inset.length > 0) {
doFillArea(promises, inset, angle || auto, spacing, poly.fill = []);
if (!outline && poly.fill.length) {
poly.fill = connect_lines(poly.fill, spacing * 2);
}
}
return true;
});

View file

@ -1862,10 +1862,10 @@ gapp.register("kiri.init", [], (root, exports) => {
sliceSupportArea: uc.newInput(LANG.sp_area_s, {title:LANG.sp_area_l, bound:uc.bound(0.0,200.0), convert:uc.toFloat, modes:FDM}),
sliceSupportExtra: uc.newInput(LANG.sp_xpnd_s, {title:LANG.sp_xpnd_l, bound:uc.bound(0.0,200.0), convert:uc.toFloat, modes:FDM}),
fdmSep: uc.newBlank({class:"pop-sep", modes:FDM}),
sliceSupportAngle: uc.newInput(LANG.sp_angl_s, {title:LANG.sp_angl_l, bound:uc.bound(0.0,90.0), convert:uc.toFloat, modes:FDM, show:() => !ui.sliceSupportEnable.checked}),
sliceSupportAngle: uc.newInput(LANG.sp_angl_s, {title:LANG.sp_angl_l, bound:uc.bound(0.0,90.0), convert:uc.toFloat, modes:FDM}),
sliceSupportSpan: uc.newInput(LANG.sp_span_s, {title:LANG.sp_span_l, bound:uc.bound(0.0,200.0), convert:uc.toFloat, modes:FDM, show:() => ui.sliceSupportEnable.checked}),
sliceSupportEnable: uc.newBoolean(LANG.sp_auto_s, onBooleanClick, {title:LANG.sp_auto_l, modes:FDM, show:isNotBelt}),
sliceSupportOutline: uc.newBoolean(LANG.sp_outl_s, onBooleanClick, {title:LANG.sp_outl_l, modes:FDM, show:() => !ui.sliceSupportEnable.checked}),
sliceSupportOutline: uc.newBoolean(LANG.sp_outl_s, onBooleanClick, {title:LANG.sp_outl_l, modes:FDM}),
sliceSupportGen: uc.newRow([
ui.ssaGen = uc.newButton(LANG.sp_detect, onButtonClick, {class: "f-col grow a-center"})