refactor slice progress tracking, comment out ununsed support var, tighten slice shadow range for fdm
This commit is contained in:
parent
84f4dcbcde
commit
69fdf1a60b
4 changed files with 95 additions and 50 deletions
|
|
@ -345,7 +345,7 @@ export const conf = {
|
|||
sliceSupportNozzle: 0,
|
||||
sliceSupportOffset: 1.0,
|
||||
sliceSupportOutline: true,
|
||||
sliceSupportSpan: 5,
|
||||
// sliceSupportSpan: 5,
|
||||
sliceSupportType: "disabled",
|
||||
sliceSupportTree: false,
|
||||
sliceTopLayers: 3,
|
||||
|
|
|
|||
|
|
@ -786,7 +786,7 @@ class Widget {
|
|||
return this.cache.shadow = stack;
|
||||
}
|
||||
|
||||
async computeShadowStack(zlist, progress, pocket) {
|
||||
async computeShadowStack(zlist, progress, pocket, up = 1) {
|
||||
let shadow_stack = this.cache.shadow_stack;
|
||||
if (!shadow_stack) {
|
||||
shadow_stack = this.cache.shadow_stack = {};
|
||||
|
|
@ -803,7 +803,7 @@ class Widget {
|
|||
let p = work.minions.queueAsync({
|
||||
cmd: 'cam_shadow_z',
|
||||
z: z - 0.005,
|
||||
t: z + 1
|
||||
t: z + up
|
||||
}).then(reply => {
|
||||
shadow_stack[z - 0.005] = decode(reply.data);
|
||||
pval += pinc;
|
||||
|
|
|
|||
|
|
@ -124,9 +124,10 @@ export function menu() {
|
|||
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)}),
|
||||
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 }),
|
||||
sliceSupportOutline: newBoolean(LANG.sp_outl_s, onBooleanClick, {title:LANG.sp_outl_l, xshow: () => !isTree() }),
|
||||
sliceSupportTree: newBoolean(LANG.sp_tree_s, onBooleanClick, {title:LANG.sp_tree_l }),
|
||||
separator: newBlank({ class:"set-sep", driven, show:manualSupport }),
|
||||
sliceSupportManual: newRow([
|
||||
(ui.ssmAdd = newButton(undefined, onButtonClick, {icon:'<i class="fas fa-plus"></i>'})),
|
||||
|
|
|
|||
|
|
@ -173,6 +173,29 @@ function vopt(opt, ctx) {
|
|||
return opt;
|
||||
}
|
||||
|
||||
/**
|
||||
* return percentage values broken into ranges
|
||||
*
|
||||
* @param {number} plo 0.0-1.0 percentage value
|
||||
* @param {number} phi 0.0-1.0 high percentage value
|
||||
* @param {Array} pcts [{ lo, hi }, ...]
|
||||
*/
|
||||
function divide(plo, phi, pcts) {
|
||||
let sum = 0;
|
||||
let lo = plo;
|
||||
let rval = pcts.map(pct => {
|
||||
sum += pct;
|
||||
let diff = (phi - plo) * pct;
|
||||
let rval = { lo, hi: lo + diff };
|
||||
lo += diff;
|
||||
return rval;
|
||||
});
|
||||
if (Math.abs(1 - sum) > 0.001) {
|
||||
console.log('SUM FAIL', { rval, sum });
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* DRIVER SLICE CONTRACT
|
||||
*
|
||||
|
|
@ -441,17 +464,18 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
|||
}).filter(s => s);
|
||||
}
|
||||
|
||||
// slicing is the first 50% of the update "time"
|
||||
function trackupdate(pct, from, to, msg) {
|
||||
// console.log(from.round(2), to.round(2), msg);
|
||||
onupdate(0.5 + (from + (pct * (to - from))) * 0.5, msg);
|
||||
}
|
||||
|
||||
// calculate % complete and call onupdate()
|
||||
function doupdate(index, from, to, msg) {
|
||||
trackupdate(index / slices.length, from, to, msg);
|
||||
}
|
||||
|
||||
// slicing is the first 50% of the update "time"
|
||||
function trackupdate(pct, from, to, msg) {
|
||||
onupdate(0.5 + (from + (pct * (to - from))) * 0.5, msg);
|
||||
}
|
||||
|
||||
// for each slice, performe a function and call doupdate()
|
||||
// for each slice, perform a function and call doupdate()
|
||||
function forSlices(from, to, fn, msg) {
|
||||
slices.forEach(slice => {
|
||||
fn(slice);
|
||||
|
|
@ -462,11 +486,12 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
|||
/**
|
||||
* Process automatic and manual shadow-based support generation
|
||||
*/
|
||||
async function processSupports() {
|
||||
async function processSupports(plo, phi) {
|
||||
if (process.sliceSupportType === 'disabled') {
|
||||
return;
|
||||
}
|
||||
|
||||
let div = divide(plo, phi, [ 0.5, 0.5 ]);
|
||||
let stack = slices.slice();
|
||||
let indices = stack.map(s => s.z);
|
||||
let zAngNorm = Math.sin(process.sliceSupportAngle * Math.PI / 180);
|
||||
|
|
@ -517,8 +542,8 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
|||
// create automatic shadows supports when on manual paint
|
||||
if (!manual) {
|
||||
await widget.computeShadowStack(indices, progress => {
|
||||
trackupdate(progress, 0.05, 0.10, "shadow");
|
||||
}, zAngNorm);
|
||||
trackupdate(progress, div[0].lo, div[0].hi, "shadow");
|
||||
}, zAngNorm, sliceHeight);
|
||||
|
||||
for (let slice of stack) {
|
||||
slice.shadow = await widget.shadowAt(slice.z, true);
|
||||
|
|
@ -532,9 +557,15 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
|||
let length = stack.length;
|
||||
let count = 0;
|
||||
|
||||
// convert shadows to trees, when specified
|
||||
if (process.sliceSupportTree) {
|
||||
// console.log('TREE OUTPUT');
|
||||
}
|
||||
|
||||
// perform accumulation top down
|
||||
for (let slice of stack.reverse()) {
|
||||
let shadow = slice.shadow ?? [];
|
||||
if (devel) slice.output().setLayer("shadow", 0xff0000).addPolys(shadow.clone(true));
|
||||
if (process.sliceSupportExtra) {
|
||||
shadow = POLY.offset(shadow, process.sliceSupportExtra);
|
||||
}
|
||||
|
|
@ -545,11 +576,7 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
|||
// subtract slice.clips areas (widget boundaries) from shadow projection
|
||||
if (true) {
|
||||
let rem = [];
|
||||
let clips = [
|
||||
slice.up?.clips,
|
||||
slice.clips,
|
||||
slice.down?.clips
|
||||
].filter(v => v).flat();
|
||||
let clips = [ slice.clips ].filter(v => v).flat();
|
||||
clips = POLY.union(clips, minArea, true);
|
||||
POLY.subtract(shadow, clips, rem, null, slice.z, minArea, { wasm: false });
|
||||
shadow = rem;
|
||||
|
|
@ -573,8 +600,22 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
|||
if (devel) slice.output().setLayer("belt clip", 0xffff00).addPolys([ clip ]);
|
||||
}
|
||||
slice.supports = shadow;
|
||||
if (devel) slice.output().setLayer("shadow", 0xff0000).addPolys(shadow);
|
||||
trackupdate((++count/length), 0.10, 0.15, "support");
|
||||
// if (devel) slice.output().setLayer("shadow", 0xff0000).addPolys(shadow);
|
||||
trackupdate((++count/length), div[1].lo, div[1].hi, "support");
|
||||
}
|
||||
|
||||
// clip shadow to layers above/below clip areas (for part separation)
|
||||
for (let slice of stack.reverse()) {
|
||||
let clips = [
|
||||
slice.up?.clips,
|
||||
slice.down?.clips
|
||||
].filter(v => v).flat();
|
||||
if (clips.length) {
|
||||
let rem = [];
|
||||
clips = POLY.union(clips, minArea, true);
|
||||
POLY.subtract(slice.supports, clips, rem, null, slice.z, minArea, { wasm: false });
|
||||
slice.supports = rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -582,8 +623,8 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
|||
* Process top and bottom layers or any other
|
||||
* layers detected and marked for solid fill
|
||||
*/
|
||||
async function processSolidLayers() {
|
||||
forSlices(0.15, 0.2, slice => {
|
||||
async function processSolidLayers(plo, phi) {
|
||||
forSlices(plo, phi, slice => {
|
||||
let range = slice.params;
|
||||
let isBottom = slice.index < bottomLayers;
|
||||
let isTop = topLayers && slice.index > slices.length - topLayers - 1;
|
||||
|
|
@ -604,10 +645,11 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
|||
/**
|
||||
* Process layer diffs and project solid areas
|
||||
*/
|
||||
async function processLayerDiffs() {
|
||||
async function processLayerDiffs(plo, phi) {
|
||||
let div = divide(plo, phi, [ 0.9, 0.05, 0.05 ]);
|
||||
// boolean diff layers to detect bridges and flats
|
||||
profileStart("delta");
|
||||
forSlices(0.2, 0.33, slice => {
|
||||
forSlices(div[0].lo, div[1].hi, slice => {
|
||||
let params = slice.params || process;
|
||||
let solidMinArea = params.sliceSolidMinArea;
|
||||
let sliceMinThick = params.sliceSolidMinThick;
|
||||
|
|
@ -617,7 +659,7 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
|||
profileEnd();
|
||||
// project bridges and flats up and down into part
|
||||
profileStart("delta-project");
|
||||
forSlices(0.33, 0.34, slice => {
|
||||
forSlices(div[1].lo, div[1].hi, slice => {
|
||||
let params = slice.params || process;
|
||||
topLayers = params.sliceTopLayers || 0;
|
||||
bottomLayers = params.sliceBottomLayers || 0;
|
||||
|
|
@ -628,7 +670,7 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
|||
profileEnd();
|
||||
// union solid areas
|
||||
profileStart("solid-union");
|
||||
forSlices(0.34, 0.35, slice => {
|
||||
forSlices(div[2].lo, div[2].hi, slice => {
|
||||
if (slice.solids) {
|
||||
slice.solids = POLY.union(slice.solids, 0, true);
|
||||
}
|
||||
|
|
@ -639,10 +681,11 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
|||
/**
|
||||
* Process solid fill patterns
|
||||
*/
|
||||
async function processSolidFills() {
|
||||
async function processSolidFills(plo, phi) {
|
||||
profileStart("solid-fill")
|
||||
let promises = isConcurrent ? [] : undefined;
|
||||
forSlices(0.35, promises ? 0.4 : 0.5, slice => {
|
||||
let div = divide(plo, phi, promises ? [ 0.8, 0.2 ] : [ 1 ]);
|
||||
forSlices(div[0].lo, div[0].hi, slice => {
|
||||
let params = slice.params || process;
|
||||
let solidWidth = params.sliceFillWidth || 1;
|
||||
let fillSpace = fillSpacing * solidWidth;
|
||||
|
|
@ -654,7 +697,7 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
|||
slices.last().finishSolids = true
|
||||
if (promises) {
|
||||
await tracker(promises, (i, t) => {
|
||||
trackupdate(i / t, 0.4, 0.5);
|
||||
trackupdate(i / t, div[1].lo, div[1].hi);
|
||||
});
|
||||
}
|
||||
profileEnd();
|
||||
|
|
@ -663,10 +706,11 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
|||
/**
|
||||
* Process sparse infill patterns
|
||||
*/
|
||||
async function processSparseInfill() {
|
||||
async function processSparseInfill(plo, phi) {
|
||||
let lastType;
|
||||
let promises = isConcurrent ? [] : undefined;
|
||||
forSlices(0.5, promises ? 0.55 : 0.7, slice => {
|
||||
let div = divide(plo, phi, promises ? [ 0.8, 0.2 ] : [ 1 ]);
|
||||
forSlices(div[0].lo, div[0].hi, slice => {
|
||||
let params = slice.params || process;
|
||||
if (!params.sliceFillSparse) {
|
||||
return;
|
||||
|
|
@ -689,7 +733,7 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
|||
}, "infill");
|
||||
if (promises) {
|
||||
await tracker(promises, (i, t) => {
|
||||
trackupdate(i / t, 0.55, 0.7);
|
||||
trackupdate(i / t, div[1].lo, div[1].hi);
|
||||
});
|
||||
}
|
||||
// filter out tiny fill points less than nozzle diameter
|
||||
|
|
@ -715,10 +759,11 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
|||
/**
|
||||
* Process support structure fills
|
||||
*/
|
||||
async function processSupportFills() {
|
||||
async function processSupportFills(plo, phi) {
|
||||
profileStart("support-fill");
|
||||
let promises = false && isConcurrent ? [] : undefined;
|
||||
forSlices(0.8, promises ? 0.88 : 0.9, slice => {
|
||||
let div = divide(plo, phi, promises ? [ 0.8, 0.2 ] : [ 1 ]);
|
||||
forSlices(div[0].lo, div[0].hi, slice => {
|
||||
let params = slice.params || process;
|
||||
let density = params.sliceSupportDensity;
|
||||
layerSupportFill({
|
||||
|
|
@ -733,7 +778,7 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
|||
}, "support fill");
|
||||
if (promises) {
|
||||
await tracker(promises, (i, t) => {
|
||||
trackupdate(i / t, 0.88, 0.9);
|
||||
trackupdate(i / t, div[1].lo, div[1].hi);
|
||||
});
|
||||
}
|
||||
profileEnd();
|
||||
|
|
@ -788,8 +833,8 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
|||
slices.forEach((s,i) => s.index = i);
|
||||
}
|
||||
|
||||
async function renderSlices() {
|
||||
forSlices(0.9, 1.0, slice => {
|
||||
async function renderSlices(plo, phi) {
|
||||
forSlices(plo, phi, slice => {
|
||||
let params = slice.params || process;
|
||||
layerRender(slice, params, {
|
||||
dark: controller.dark,
|
||||
|
|
@ -850,7 +895,7 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
|||
}
|
||||
|
||||
// process solid layers (top/bottom)
|
||||
await processSolidLayers();
|
||||
await processSolidLayers(0.10, 0.20);
|
||||
|
||||
// add lead in anchor when specified in belt mode (but not for synths)
|
||||
if (isBelt) {
|
||||
|
|
@ -883,10 +928,6 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
|||
});
|
||||
}
|
||||
|
||||
// support generation using either
|
||||
// enclosed shadow or manual painted supports
|
||||
await processSupports();
|
||||
|
||||
// calculations only relevant when solid layers are used
|
||||
// layer boolean diffs need to be computed to find flat areas to fill
|
||||
// and overhangs that need to be supported. these are stored in flats
|
||||
|
|
@ -894,24 +935,27 @@ export function sliceOne(settings, widget, onupdate, ondone) {
|
|||
// for "real" objects, fill the remaining voids with sparse fill
|
||||
// sparse layers only present when non-vase mode and sparse % > 0
|
||||
if (!vaseMode) {
|
||||
await processLayerDiffs();
|
||||
await processSolidFills();
|
||||
await processSparseInfill();
|
||||
await processLayerDiffs(0.2, 0.4);
|
||||
// support generation using either
|
||||
// enclosed shadow or manual painted supports
|
||||
await processSupports(0.4, 0.5);
|
||||
await processSolidFills(0.5, 0.6);
|
||||
await processSparseInfill(0.6, 0.8);
|
||||
}
|
||||
|
||||
// fill all supports (auto and manual)
|
||||
if (supportDensity) {
|
||||
await processSupportFills();
|
||||
await processSupportFills(0.8, 0.84);
|
||||
}
|
||||
|
||||
// brick/interleave mode processing
|
||||
if (isBrick) {
|
||||
await processBrickMode();
|
||||
await processBrickMode(0.84, 0.85);
|
||||
}
|
||||
|
||||
// render if not explicitly disabled
|
||||
if (render) {
|
||||
await renderSlices();
|
||||
await renderSlices(0.85, 1.0);
|
||||
}
|
||||
|
||||
if (isBelt) {
|
||||
|
|
@ -1384,10 +1428,10 @@ export function layerDiff(slice, options = {}) {
|
|||
newFlats = newFlats.filter(p => p.areaDeep() >= area && p.thickness(true) >= thick);
|
||||
|
||||
if (grow > 0 && newBridges.length) {
|
||||
newBridges = POLY.offset(newBridges, grow);
|
||||
newBridges = POLY.offset(newBridges, grow, { z: slice.z });
|
||||
}
|
||||
if (grow > 0 && newFlats.length) {
|
||||
newFlats = POLY.offset(newFlats, grow);
|
||||
newFlats = POLY.offset(newFlats, grow, { z: slice.z });
|
||||
}
|
||||
|
||||
bridges.appendAll(newBridges);
|
||||
|
|
|
|||
Loading…
Reference in a new issue