diff --git a/src/kiri-mode/fdm/post.js b/src/kiri-mode/fdm/post.js index 2b0e6d5f..4b25ad4a 100644 --- a/src/kiri-mode/fdm/post.js +++ b/src/kiri-mode/fdm/post.js @@ -53,14 +53,14 @@ base.slicePost.FDM = function(data, options) { const count = isSynth ? 1 : sliceShells; const offset = shellOffset * spaceMult; const fillOff = fillOffset * spaceMult; + const thinType = isSynth ? undefined : process.sliceDetectThin; const nutops = []; // co-locate shell processing with top generation in slicer for (let top of data.tops) { nutops.push(FDM.doTopShells(z, top, count, offset/2, offset, fillOff, { - vase: vaseMode, - thin: process.detectThinWalls && !isSynth, - wasm: useAssembly, - danger: isDanger + thinType, + vaseMode, + useAssembly })); } data.clip = clipOffset ? POLY.offset(nutops.map(t => t.simple), clipOffset) : undefined; @@ -81,10 +81,10 @@ FDM.doTopShells = function(z, top, count, offset1, offsetN, fillOffset, opt = {} // add simple (low rez poly) where less accuracy is OK top.simple = top.poly.simple(); - let wasm = opt.wasm; + let wasm = opt.useAssembly; let top_poly = [ top.poly ]; - if (opt.vase) { + if (opt.vaseMode) { // remove top poly inners in vase mode top.poly = top.poly.clone(false); } @@ -107,82 +107,86 @@ FDM.doTopShells = function(z, top, count, offset1, offsetN, fillOffset, opt = {} let dist = p.first().distTo2D(p.last()); if (dist < 1) p.open = false; } }); - if (opt.danger && opt.thin) { - top.thin_fill = []; - top.fill_sparse = []; - let layers = POLY.inset(top_poly, offsetN, count, z, true); - last = layers.last().mid; - top.shells = layers.map(r => r.mid).flat(); - top.gaps = layers.map(r => r.gap).flat(); - let off = offsetN; - let min = off * 0.75; - let max = off * 4; - for (let poly of layers.map(r => r.gap).flat()) { - let centers = poly.centers(off/2, z, min, max, {lines:false}); - top.fill_sparse.appendAll(centers); - // top.fill_lines.appendAll(centers); - } - } else if (opt.thin) { - top.thin_fill = []; - let oso = {z, count, gaps: [], outs: [], minArea: 0.05, wasm}; - POLY.offset(top_poly, [-offset1, -offsetN], oso); + switch (opt.thinType) { + case "type 1": + top.thin_fill = []; + top.fill_sparse = []; + let layers = POLY.inset(top_poly, offsetN, count, z, true); + last = layers.last().mid; + top.shells = layers.map(r => r.mid).flat(); + top.gaps = layers.map(r => r.gap).flat(); + let off = offsetN; + let min = off * 0.75; + let max = off * 4; + for (let poly of layers.map(r => r.gap).flat()) { + let centers = poly.centers(off/2, z, min, max, {lines:false}); + top.fill_sparse.appendAll(centers); + // top.fill_lines.appendAll(centers); + } + break; + case "type 2": + top.thin_fill = []; + let oso = {z, count, gaps: [], outs: [], minArea: 0.05, wasm}; + POLY.offset(top_poly, [-offset1, -offsetN], oso); - oso.outs.forEach((polys, i) => { - polys.forEach(p => { - p.depth = i; - if (p.fill_off) { - p.fill_off.forEach(pi => pi.depth = i); - } - if (p.inner) { - for (let pi of p.inner) { - pi.depth = p.depth; + oso.outs.forEach((polys, i) => { + polys.forEach(p => { + p.depth = i; + if (p.fill_off) { + p.fill_off.forEach(pi => pi.depth = i); } - } - top.shells.push(p); + if (p.inner) { + for (let pi of p.inner) { + pi.depth = p.depth; + } + } + top.shells.push(p); + }); + last = polys; }); - last = polys; - }); - // slice.solids.trimmed = slice.solids.trimmed || []; - oso.gaps.forEach((polys, i) => { - let off = (i == 0 ? offset1 : offsetN); - polys = POLY.offset(polys, -off * 0.8, {z, minArea: 0, wasm}); - top.thin_fill.appendAll(cullIntersections( - fillArea(polys, 45, off/2, [], 0.01, off*2), - fillArea(polys, 135, off/2, [], 0.01, off*2), - )); - gaps = polys; - }); - } else { - // standard wall offsetting strategy - POLY.offset( - top_poly, - [-offset1, -offsetN], - { - z, - wasm, - count, - outs: top.shells, - flat: true, - call: (polys, onCount) => { - last = polys; - // mark each poly with depth (offset #) starting at 0 - for (let p of polys) { - p.depth = count - onCount; - if (p.fill_off) p.fill_off.forEach(function(pi) { - // use negative offset for inners - pi.depth = -(count - onCount); - }); - // mark inner depth to match parent - if (p.inner) { - for (let pi of p.inner) { - pi.depth = p.depth; + // slice.solids.trimmed = slice.solids.trimmed || []; + oso.gaps.forEach((polys, i) => { + let off = (i == 0 ? offset1 : offsetN); + polys = POLY.offset(polys, -off * 0.8, {z, minArea: 0, wasm}); + top.thin_fill.appendAll(cullIntersections( + fillArea(polys, 45, off/2, [], 0.01, off*2), + fillArea(polys, 135, off/2, [], 0.01, off*2), + )); + gaps = polys; + }); + break; + default: + // standard wall offsetting strategy + POLY.offset( + top_poly, + [-offset1, -offsetN], + { + z, + wasm, + count, + outs: top.shells, + flat: true, + call: (polys, onCount) => { + last = polys; + // mark each poly with depth (offset #) starting at 0 + for (let p of polys) { + p.depth = count - onCount; + if (p.fill_off) p.fill_off.forEach(function(pi) { + // use negative offset for inners + pi.depth = -(count - onCount); + }); + // mark inner depth to match parent + if (p.inner) { + for (let pi of p.inner) { + pi.depth = p.depth; + } } } } } - } - ); + ); + break; } } } else { @@ -210,4 +214,52 @@ FDM.doTopShells = function(z, top, count, offset1, offsetN, fillOffset, opt = {} return top; } +/** + * given an array of arrays of points (lines), eliminate intersections + * between groups, then return a unified array of shortest non-intersects. + */ +function cullIntersections() { + function toLines(pts) { + let lns = []; + for (let i=0, il=pts.length; i t); + if (aOa.length < 1) return; + let aa = toLines(aOa.shift()); + while (aOa.length) { + let bb = toLines(aOa.shift()); + loop: for (let i=0, il=aa.length; i !l.del).concat(bb.filter(l => !l.del)); + } + let good = []; + for (let i=0, il=aa.length; i 2 ? good : []; +} + }); diff --git a/src/kiri-mode/fdm/slice.js b/src/kiri-mode/fdm/slice.js index a934c1d0..0c7e5827 100644 --- a/src/kiri-mode/fdm/slice.js +++ b/src/kiri-mode/fdm/slice.js @@ -1446,56 +1446,6 @@ function projectSolid(slice, polys, count, up, first) { } } -/** - * given an array of arrays of points (lines), eliminate intersections - * between groups, then return a unified array of shortest non-intersects. - * - * @returns {Point[]} - */ -function cullIntersections() { - function toLines(pts) { - let lns = []; - for (let i=0, il=pts.length; i t); - if (aOa.length < 1) return; - let aa = toLines(aOa.shift()); - while (aOa.length) { - let bb = toLines(aOa.shift()); - loop: for (let i=0, il=aa.length; i !l.del).concat(bb.filter(l => !l.del)); - } - let good = []; - for (let i=0, il=aa.length; i 2 ? good : []; -} - FDM.supports = function(settings, widget) { let isBelt = settings.device.bedBelt; let process = settings.process; diff --git a/src/kiri/conf.js b/src/kiri/conf.js index 4a13af17..289b6663 100644 --- a/src/kiri/conf.js +++ b/src/kiri/conf.js @@ -364,7 +364,7 @@ const conf = exports({ outputLoops: 0, outputInvertX: false, outputInvertY: false, - detectThinWalls: false, + sliceDetectThin: "off", sliceMinHeight: 0, sliceAdaptive: false, zHopDistance: 0.2, diff --git a/src/kiri/consts.js b/src/kiri/consts.js index c1c5cec6..d46fa1cc 100644 --- a/src/kiri/consts.js +++ b/src/kiri/consts.js @@ -97,6 +97,11 @@ const LISTS = { { name: "2" }, { name: "3" } ], + thin: [ + { name: "off" }, + { name: "type 1" }, + { name: "type 2" } + ] }; // primary device mode diff --git a/src/kiri/init.js b/src/kiri/init.js index 9ca58baf..7ba020af 100644 --- a/src/kiri/init.js +++ b/src/kiri/init.js @@ -117,6 +117,15 @@ gapp.register("kiri.init", [], (root, exports) => { filamentSourceEditUpdate(); } + function thinWallSave() { + let opt = ui.sliceDetectThin; + let level = opt.options[opt.selectedIndex]; + if (level) { + settings().process.sliceDetectThin = level.value; + api.conf.save(); + } + } + function detailSave() { let level = ui.detail.options[ui.detail.selectedIndex]; if (level) { @@ -1742,8 +1751,8 @@ gapp.register("kiri.init", [], (root, exports) => { sliceSolidLayers: uc.newInput(LANG.sl_lsld_s, {title:LANG.sl_lsld_l, convert:uc.toInt, modes:FDM}), sliceBottomLayers: uc.newInput(LANG.sl_lbot_s, {title:LANG.sl_lbot_l, convert:uc.toInt, modes:FDM}), fdmSep: uc.newBlank({class:"pop-sep", modes:FDM}), + sliceDetectThin: uc.newSelect(LANG.ad_thin_s, {title: LANG.ad_thin_l, action: thinWallSave}, "thin"), sliceAdaptive: uc.newBoolean(LANG.ad_adap_s, onBooleanClick, {title: LANG.ad_adap_l, modes:FDM, trigger: true}), - detectThinWalls: uc.newBoolean(LANG.ad_thin_s, onBooleanClick, {title: LANG.ad_thin_l, modes:FDM}), laserOffset: uc.newInput(LANG.ls_offs_s, {title:LANG.ls_offs_l, convert:uc.toFloat, modes:LASER}), laserSliceHeight: uc.newInput(LANG.ls_lahi_s, {title:LANG.ls_lahi_l, convert:uc.toFloat, modes:LASER, trigger: true}), diff --git a/web/kiri/lang/en.js b/web/kiri/lang/en.js index 6a275821..a272a029 100644 --- a/web/kiri/lang/en.js +++ b/web/kiri/lang/en.js @@ -318,7 +318,7 @@ self.kiri.lang['en-us'] = { sl_ordr_l: ["output shell order","inside to outside","or outside to inside","affects surface quality"], sl_strt_s: "layer start", sl_strt_l: ["layer starting point","last = last layer end","center = part center","origin = device origin"], - ad_thin_s: "thin walls", + ad_thin_s: "thin wall", ad_thin_l: ["detect and fill gaps","between shell walls"], // FDM FILL