From 8a4e5a053f9cd86a6ea8288fa769d1e86537778c Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Sun, 14 Jan 2018 13:15:05 -0500 Subject: [PATCH] improve thin wall detection --- js/geo-polygons.js | 12 ++++++------ js/kiri-codec.js | 2 ++ js/kiri-driver-fdm.js | 12 ++++++++++-- js/kiri-print.js | 4 ++-- js/kiri-slice.js | 35 ++++++++++++++++++----------------- js/kiri.js | 22 ++++++++++++---------- notes.md | 4 +--- 7 files changed, 51 insertions(+), 40 deletions(-) diff --git a/js/geo-polygons.js b/js/geo-polygons.js index 664b3aba..ab234d86 100644 --- a/js/geo-polygons.js +++ b/js/geo-polygons.js @@ -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; diff --git a/js/kiri-codec.js b/js/kiri-codec.js index 8efa3df7..c27a691e 100644 --- a/js/kiri-codec.js +++ b/js/kiri-codec.js @@ -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); diff --git a/js/kiri-driver-fdm.js b/js/kiri-driver-fdm.js index 37549a98..35c83930 100644 --- a/js/kiri-driver-fdm.js +++ b/js/kiri-driver-fdm.js @@ -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), diff --git a/js/kiri-print.js b/js/kiri-print.js index 3a0585eb..8d950ae7 100644 --- a/js/kiri-print.js +++ b/js/kiri-print.js @@ -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 { diff --git a/js/kiri-slice.js b/js/kiri-slice.js index 8401d31e..1a544577 100644 --- a/js/kiri-slice.js +++ b/js/kiri-slice.js @@ -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= 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}), diff --git a/notes.md b/notes.md index a093cfc5..d0528bba 100644 --- a/notes.md +++ b/notes.md @@ -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