add thin wall pull-type to allow for multiple strategies
This commit is contained in:
parent
0de4445256
commit
074dc2c99d
6 changed files with 145 additions and 129 deletions
|
|
@ -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<il; i += 2) {
|
||||
lns.push({a: pts[i], b: pts[i+1], l: pts[i].distTo2D(pts[i+1])});
|
||||
}
|
||||
return lns;
|
||||
}
|
||||
let aOa = [...arguments].filter(t => 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<il; i++) {
|
||||
let al = aa[i];
|
||||
if (al.del) {
|
||||
continue;
|
||||
}
|
||||
for (let j=0, jl=bb.length; j<jl; j++) {
|
||||
let bl = bb[j];
|
||||
if (bl.del) {
|
||||
continue;
|
||||
}
|
||||
if (util.intersect(al.a, al.b, bl.a, bl.b, base.key.SEGINT)) {
|
||||
if (al.l < bl.l) {
|
||||
bl.del = true;
|
||||
} else {
|
||||
al.del = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
aa = aa.filter(l => !l.del).concat(bb.filter(l => !l.del));
|
||||
}
|
||||
let good = [];
|
||||
for (let i=0, il=aa.length; i<il; i++) {
|
||||
let al = aa[i];
|
||||
good.push(al.a);
|
||||
good.push(al.b);
|
||||
}
|
||||
return good.length > 2 ? good : [];
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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<il; i += 2) {
|
||||
lns.push({a: pts[i], b: pts[i+1], l: pts[i].distTo2D(pts[i+1])});
|
||||
}
|
||||
return lns;
|
||||
}
|
||||
let aOa = [...arguments].filter(t => 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<il; i++) {
|
||||
let al = aa[i];
|
||||
if (al.del) {
|
||||
continue;
|
||||
}
|
||||
for (let j=0, jl=bb.length; j<jl; j++) {
|
||||
let bl = bb[j];
|
||||
if (bl.del) {
|
||||
continue;
|
||||
}
|
||||
if (util.intersect(al.a, al.b, bl.a, bl.b, base.key.SEGINT)) {
|
||||
if (al.l < bl.l) {
|
||||
bl.del = true;
|
||||
} else {
|
||||
al.del = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
aa = aa.filter(l => !l.del).concat(bb.filter(l => !l.del));
|
||||
}
|
||||
let good = [];
|
||||
for (let i=0, il=aa.length; i<il; i++) {
|
||||
let al = aa[i];
|
||||
good.push(al.a);
|
||||
good.push(al.b);
|
||||
}
|
||||
return good.length > 2 ? good : [];
|
||||
}
|
||||
|
||||
FDM.supports = function(settings, widget) {
|
||||
let isBelt = settings.device.bedBelt;
|
||||
let process = settings.process;
|
||||
|
|
|
|||
|
|
@ -364,7 +364,7 @@ const conf = exports({
|
|||
outputLoops: 0,
|
||||
outputInvertX: false,
|
||||
outputInvertY: false,
|
||||
detectThinWalls: false,
|
||||
sliceDetectThin: "off",
|
||||
sliceMinHeight: 0,
|
||||
sliceAdaptive: false,
|
||||
zHopDistance: 0.2,
|
||||
|
|
|
|||
|
|
@ -97,6 +97,11 @@ const LISTS = {
|
|||
{ name: "2" },
|
||||
{ name: "3" }
|
||||
],
|
||||
thin: [
|
||||
{ name: "off" },
|
||||
{ name: "type 1" },
|
||||
{ name: "type 2" }
|
||||
]
|
||||
};
|
||||
|
||||
// primary device mode
|
||||
|
|
|
|||
|
|
@ -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}),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue