improve thin wall detection

This commit is contained in:
Stewart Allen 2018-01-14 13:15:05 -05:00
commit 8a4e5a053f
7 changed files with 51 additions and 40 deletions

View file

@ -447,7 +447,6 @@ var gs_base_polygons = exports;
* @param {Polygon[]} polys
* @param {number} dist1 first offset distance
* @param {number} dist2 2nd thru last offset distance
* @param {number} over additional offset over then under
* @param {Polygon[]} out optional collector
* @param {number} count offset passes (0 == until no space left)
* @param {Function} collector receives output of each pass
@ -455,7 +454,7 @@ var gs_base_polygons = exports;
* @param {number} [z] defaults to 0
* @returns {Polygon[]} last offset
*/
function expand2(polys, dist1, dist2, over, out, count, collector, thins, z) {
function expand2(polys, dist1, dist2, out, count, collector, thins, z) {
// prepare alignments for clipper lib
alignWindings(polys);
polys.forEach(function(poly) {
@ -470,7 +469,8 @@ var gs_base_polygons = exports;
cety = clib.EndType,
coff = new clib.ClipperOffset(),
ctre = new clib.PolyTree(),
orig = polys;
orig = polys,
over = dist1 * 0.45;
// inset
polys.forEach(function(poly) {
@ -489,7 +489,7 @@ var gs_base_polygons = exports;
var simple = clip.SimplifyPolygons(clean, cpft.pftNonZero);
coff.AddPaths(simple, cjnt.jtMiter, cety.etClosedPolygon);
});
coff.Execute(ctre, (-over) * fact);
coff.Execute(ctre, -over * fact);
polys = fromClipperTree(ctre, z);
// detect possible thin walls
@ -499,7 +499,7 @@ var gs_base_polygons = exports;
diff = Math.abs(1 - (circ1 / circ2));
if (diff > 0.2) {
thins(orig, polys, diff);
thins(orig, out.length ? polys : null, diff, -over);
}
}
@ -507,7 +507,7 @@ var gs_base_polygons = exports;
if (out) out.appendAll(polys);
if (collector) collector(polys, count);
if ((count === 0 || count > 1) && polys.length > 0) {
expand2(polys, dist2 || dist1, dist2, over, out, count > 0 ? count-1 : 0, collector, thins, z);
expand2(polys, dist2 || dist1, dist2, out, count > 0 ? count-1 : 0, collector, thins, z);
}
return polys;

View file

@ -120,6 +120,7 @@ var gs_kiri_codec = exports;
poly: encode(this.poly, state),
traces: encode(this.traces, state),
inner: encode(this.inner, state),
// thinner: encode(this.thinner, state),
solids: encode(this.solids, state),
fill_lines: encodePointArray(this.fill_lines),
fill_sparse: encode(this.fill_sparse, state)
@ -131,6 +132,7 @@ var gs_kiri_codec = exports;
top.traces = decode(v.traces, state);
top.inner = decode(v.inner, state);
// top.thinner = decode(v.thinner, state);
top.solids = decode(v.solids, state);
top.fill_lines = decodePointArray(v.fill_lines,state);
top.fill_sparse = decode(v.fill_sparse, state);

View file

@ -216,19 +216,27 @@ var gs_kiri_fdm = exports;
polys = [],
preout = [];
// compute first brim
widgets.forEach(function(widget) {
var tops = [];
// collect top outer polygons
widget.slices[0].tops.forEach(function(top) {
tops.push(top.poly.clone());
});
// nest and offset tops
POLY.nest(tops).forEach(function(poly) {
poly.offset(-process.outputBrimOffset+device.nozzleSize/2).forEach(function(brim) {
poly.offset(-process.outputBrimOffset + device.nozzleSize/2).forEach(function(brim) {
brim.move(widget.mesh.position);
brims.push(brim);
});
});
});
// if brim is offset, the expand and shrink to cause brims to merge
if (process.outputBrimOffset && brims.length) {
}
POLY.union(brims).forEach(function(brim) {
POLY.trace2count(brim, polys, -device.nozzleSize, process.outputBrimCount, 0);
});
@ -329,7 +337,7 @@ var gs_kiri_fdm = exports;
seekMMM = process.outputSeekrate * 60,
retDist = process.outputRetractDist,
retSpeed = process.outputRetractSpeed * 60,
retDwell = Math.round((process.outputRetractDwell || 0) * 1000),
retDwell = process.outputRetractDwell || 0,
// ratio of nozzle area to filament area times
// ratio of slice height to filament max noodle height
emitPerMM = print.extrudePerMM(device.nozzleSize, device.filamentSize, process.sliceHeight),

View file

@ -634,7 +634,7 @@ var gs_kiri_print = exports;
// if dist to new segment is less than thinWall
// and segment length is less than thinWall then
// just extrude to midpoint of next segment. this is
// to avoid shaking printer to death.
// to avoid shaking the printer to death.
if (find.d <= thinWall && len <= thinWall) {
p2 = p1.midPointTo(p2);
addOutput(preout, p2, fillMult * (find.d / thinWall), printSpeed);
@ -646,7 +646,7 @@ var gs_kiri_print = exports;
checkBisect(startPoint, p1, bounds);
}
// bridge ends of fill if they're close together
// bridge ends of fill when they're close together
if (dist < thinWall) {
addOutput(preout, p1, fillMult, printSpeed);
} else {

View file

@ -340,6 +340,7 @@ var gs_kiri_slice = exports;
tops.forEach(function(top) {
layer.poly(top.poly, colors[0], true, open);
if (top.inner) layer.poly(top.inner, 0x999999, true, null);
// if (top.thinner) layer.poly(top.thinner, 0x559999, true, null);
});
break;
}
@ -357,18 +358,13 @@ var gs_kiri_slice = exports;
*/
function cullIntersections(r1, r2) {
if (!(r1 && r2 && r1.length && r2.length)) return;
if (r2.length > r1.length) {
var r3 = r1;
r1 = r2;
r2 = r3;
}
var valid = r1.slice();
outer: for (var i=0; i<r2.length; i += 2) {
for (var j=0; j<r1.length; j += 2) {
if (UTIL.intersect(r1[j], r1[j+1], r2[i], r2[i+1])) continue outer;
var valid = r2.slice();
outer: for (var i=0; i<r1.length; i += 2) {
for (var j=0; j<r2.length; j += 2) {
if (UTIL.intersect(r1[i], r1[i+1], r2[j], r2[j+1], BASE.key.SEGINT)) continue outer;
}
valid.push(r2[i]);
valid.push(r2[i+1]);
valid.push(r1[i]);
valid.push(r1[i+1]);
}
return valid;
}
@ -392,6 +388,7 @@ var gs_kiri_slice = exports;
slice.tops.forEach(function(top) {
if (opt.vase) top.poly = top.poly.clone(false);
// top.thinner = [];
top.traces = [];
top.inner = [];
var last = [],
@ -412,7 +409,6 @@ var gs_kiri_slice = exports;
[top.poly],
-offset1,
-offsetN,
-offset1,
top.traces,
count,
// on each new offset trace ...
@ -428,12 +424,17 @@ var gs_kiri_slice = exports;
});
},
// thin wall probe
function(p1, p2) {
var pall = POLY.nest([].appendAll(p1).appendAll(p2).clone(true)),
pnew = POLY.expand(pall, -offset1, z, null, 1),
r1 = fillArea(pnew, 45, offsetN, [], 0, offsetN * 2),
r2 = fillArea(pnew, 135, offsetN, [], 0, offsetN * 2),
function(p1, p2, diff, dist) {
var pall = POLY.nest(POLY.flatten([].appendAll(p1).appendAll(p2)).clone()),
pnew1 = POLY.expand(pall, -dist, z, null, 1),
r1 = fillArea(pnew1, 45, offsetN, [], 0, offset1),
r2 = fillArea(pnew1, 135, offsetN, [], 0, offset1),
rall = top.thin_fill.appendAll(cullIntersections(r1, r2)),
pnew2 = POLY.expand(pnew1, -dist, z, null, 1),
r1 = fillArea(pnew2, 45, offsetN, [], 0, offset1),
r2 = fillArea(pnew2, 135, offsetN, [], 0, offset1),
rall = top.thin_fill.appendAll(cullIntersections(r1, r2));
// top.thinner.appendAll(pnew1).appendAll(pnew2);
},
z);
} else {

View file

@ -255,9 +255,9 @@ self.kiri.license = exports.LICENSE;
sliceHeight: 0.25,
sliceShells: 2,
sliceShellSpacing: 0.9,
sliceShellSpacing: 1,
sliceFillAngle: 45,
sliceFillOverlap: 0.5,
sliceFillOverlap: 0.3,
sliceFillSpacing: 1.0,
sliceFillSparse: 0.5,
@ -278,20 +278,20 @@ self.kiri.license = exports.LICENSE;
firstSliceHeight: 0.25,
firstLayerRate: 30,
outputTemp: 230,
outputTemp: 220,
outputFanMax: 255,
outputBedTemp: 0,
outputFeedrate: 100,
outputFinishrate: 60,
outputSeekrate: 150,
outputShellMult: 1.0,
outputFillMult: 1.25,
outputSparseMult: 1.5,
outputShellMult: 1.1,
outputFillMult: 1.2,
outputSparseMult: 1.3,
outputRetractOver: 5.0,
outputRetractDist: 0.5,
outputRetractSpeed: 20,
outputRetractDwell: 0.2,
outputWipeSpeed: 20,
outputRetractDwell: 50,
outputWipeSpeed: 50,
outputWipeDistance: 0,
outputBrimCount: 2,
outputBrimOffset: 3,
@ -1011,6 +1011,7 @@ self.kiri.license = exports.LICENSE;
ajax.onreadystatechange = function() {
if (ajax.readyState === 4) {
var status = ajax.status;
STATS.add('op-'+status);
if (status >= 200 && status < 300) {
hideModal();
} else {
@ -1062,6 +1063,7 @@ self.kiri.license = exports.LICENSE;
xhtr.onreadystatechange = function() {
if (xhtr.readyState === 4) {
var status = xhtr.status;
STATS.add('gp-'+status);
if (status >= 200 && status < 300) {
var json = js2o(xhtr.responseText);
gridprint_tracker(host,json.key);
@ -1435,7 +1437,7 @@ self.kiri.license = exports.LICENSE;
function layoutPlatform(event, space) {
var layout = (viewMode === VIEWS.ARRANGE),
modified = false,
gap = space || 1,
gap = space || (1 + settings.process.sliceSupportExtra),
topZ = MODE === MODES.CAM ? camTopZ : 0;
setViewMode(VIEWS.ARRANGE);
@ -2402,7 +2404,7 @@ self.kiri.license = exports.LICENSE;
// outputRetractOver: UC.newInput("retract over", {title:"move threshold that\ntriggers retraction\n0 to disable", convert:UC.toFloat, modes:FDM}),
outputRetractDist: UC.newInput("retract dist", {title:"amount to retract filament", convert:UC.toFloat, modes:FDM}),
outputRetractSpeed: UC.newInput("retract rate", {title:"speed of filament\nretraction in mm/s", convert:UC.toInt, modes:FDM}),
outputRetractDwell: UC.newInput("retract dwell", {title:"time between re-engaging\nfilament and movement\nin seconds", convert:UC.toFloat, modes:FDM}),
outputRetractDwell: UC.newInput("retract dwell", {title:"time between re-engaging\nfilament and movement\nin milliseconds", convert:UC.toInt, modes:FDM}),
outputWipeSpeed: UC.newInput("wipe speed", {title:"speed while wiping\nnozzle in mm/s", convert:UC.toInt, modes:FDM}),
outputWipeDistance: UC.newInput("wipe distance", {title:"distance to wipe nozzle after\neach enclosed island completes\nin millimeters. 0 to disable", convert:UC.toInt, modes:FDM}),
outputShortPoly: UC.newInput("short outline", {title:"poly perimeter length\ntriggers short slowdown\nin millimeters", bound:UC.bound(0,200), convert:UC.toFloat, modes:FDM}),

View file

@ -59,10 +59,8 @@
# FDM todo
* fix thin wall support fill artifacts with complex nested polys
* post re-engage dwell (on first layer?)
* add support expand value to multi-part spacing (which defaults to 1mm)
* add lay-flat auto-rotation or from selected face
* determine start point from gcode preamble
* add rafts, manual supports
* check for support / brim intersections on first layer
* solid fill every other line, two passes. minimize heat/sag. better fill between