From 9fff3c50b53daed0daa54a0e15b2b4b6d1208986 Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Sun, 31 Dec 2017 11:27:21 -0500 Subject: [PATCH] fixes #12. add start of thin wall detection --- js/geo-polygons.js | 62 +++++++++++++++++++++++++++++++++++++++++ js/kiri-driver-cam.js | 2 +- js/kiri-driver-fdm.js | 5 +++- js/kiri-driver-laser.js | 5 ++-- js/kiri-slice.js | 57 ++++++++++++++++++++++++++++--------- js/kiri.js | 3 ++ 6 files changed, 116 insertions(+), 18 deletions(-) diff --git a/js/geo-polygons.js b/js/geo-polygons.js index 5bb5bab3..2fb6a37c 100644 --- a/js/geo-polygons.js +++ b/js/geo-polygons.js @@ -28,6 +28,7 @@ var gs_base_polygons = exports; subtract : subtract, flatten : flatten, trimTo : trimTo, + expand2 : expand2, expand : expand, union : union, nest : nest, @@ -429,6 +430,67 @@ var gs_base_polygons = exports; return polys; } + /** + * by "over" expanding then contracting, this causes shells that are too + * close together to merge and cancel out. it's a more expensive operation + * but prevents shells that are too close together to extrude properly. + * + * @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 + * @param {number} [z] defaults to 0 + * @returns {Polygon[]} last offset + */ + function expand2(polys, dist1, dist2, over, out, count, collector, z) { + // prepare alignments for clipper lib + alignWindings(polys); + polys.forEach(function(poly) { + if (poly.inner) setWinding(poly.inner, !poly.isClockwise()); + }); + + var fact = CONF.clipper, + clib = self.ClipperLib, + clip = clib.Clipper, + cpft = clib.PolyFillType, + cjnt = clib.JoinType, + cety = clib.EndType, + coff = new clib.ClipperOffset(), + ctre = new clib.PolyTree(); + + // inset + polys.forEach(function(poly) { + var clean = clip.CleanPolygons(poly.toClipper(), CONF.clipperClean); + var simple = clip.SimplifyPolygons(clean, cpft.pftNonZero); + coff.AddPaths(simple, cjnt.jtMiter, cety.etClosedPolygon); + }); + coff.Execute(ctre, (dist1 + over) * fact); + polys = fromClipperTree(ctre, z); + + // outset + coff = new clib.ClipperOffset(); + ctre = new clib.PolyTree(); + polys.forEach(function(poly) { + var clean = clip.CleanPolygons(poly.toClipper(), CONF.clipperClean); + var simple = clip.SimplifyPolygons(clean, cpft.pftNonZero); + coff.AddPaths(simple, cjnt.jtMiter, cety.etClosedPolygon); + }); + coff.Execute(ctre, (-over) * fact); + polys = fromClipperTree(ctre, z); + + // process + 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, z); + } + + return polys; + } + /** * @param {Polygon} poly input * @param {Polygon[]} traces output diff --git a/js/kiri-driver-cam.js b/js/kiri-driver-cam.js index 7ebd92ed..e4388943 100644 --- a/js/kiri-driver-cam.js +++ b/js/kiri-driver-cam.js @@ -711,7 +711,7 @@ var gs_kiri_cam = exports; shellFinish; if (sliceDepth <= 0.05) { - return ondone(null); + return ondone("invalid slice depth"); } // cut outside traces at the right points diff --git a/js/kiri-driver-fdm.js b/js/kiri-driver-fdm.js index 4cac04b9..f937d36a 100644 --- a/js/kiri-driver-fdm.js +++ b/js/kiri-driver-fdm.js @@ -107,7 +107,10 @@ var gs_kiri_fdm = exports; slice.index > slices.length - spro.sliceTopLayers-1 || spro.sliceFillSparse > 0.95 ) && !spro.sliceVase; - slice.doShells(spro.sliceShells, firstOffset, shellOffset, fillOffset, spro.sliceVase); + slice.doShells(spro.sliceShells, firstOffset, shellOffset, fillOffset, { + vase: spro.sliceVase, + thin: spro.detectThinWalls + }); if (solid) slice.doSolidLayerFill(fillSpacing, sliceFillAngle); sliceFillAngle += 90.0; }, "offsets"); diff --git a/js/kiri-driver-laser.js b/js/kiri-driver-laser.js index 584a10bf..16fa2e6a 100644 --- a/js/kiri-driver-laser.js +++ b/js/kiri-driver-laser.js @@ -30,8 +30,7 @@ var gs_kiri_laser = exports; var proc = settings.process; if (proc.laserSliceHeight < 0) { - DBUG.log("invalid slice height"); - return ondone(false); + return ondone("invalid slice height"); } SLICER.sliceWidget(widget, {height: proc.laserSliceHeight}, function(slices) { @@ -40,7 +39,7 @@ var gs_kiri_laser = exports; slice.doShells(1, -proc.laserOffset); onupdate(0.80 + (index/slices.length) * 0.20); }); - ondone(true); + ondone(); }, function(update) { onupdate(0.0 + update * 0.80) }); diff --git a/js/kiri-slice.js b/js/kiri-slice.js index 7f8467fc..df243c4b 100644 --- a/js/kiri-slice.js +++ b/js/kiri-slice.js @@ -358,12 +358,14 @@ var gs_kiri_slice = exports; * @param {number} offset1 first offset * @param {number} offsetN all subsequent offsets * @param {number} fillOffset + * @param {Obejct} options */ - PRO.doShells = function(count, offset1, offsetN, fillOffset, vase) { - var slice = this; + PRO.doShells = function(count, offset1, offsetN, fillOffset, options) { + var slice = this, + opt = options || {}; slice.tops.forEach(function(top) { - if (vase) top.poly = top.poly.clone(false); + if (opt.vase) top.poly = top.poly.clone(false); top.traces = []; top.inner = []; var last = []; @@ -374,17 +376,46 @@ var gs_kiri_slice = exports; last = [top.poly].clone(true); top.traces = last; } else { - POLY.expand([top.poly], -offset1, top.poly.getZ(), top.traces, count, -offsetN, function(polys, countNow) { - last = polys; - // mark each poly with depth (offset #) starting at 0 - polys.forEach(function(p) { - p.depth = count - countNow; - if (p.inner) p.inner.forEach(function(pi) { - // use negative offset for inners - pi.depth = -(count - countNow); + if (opt.thin) { + POLY.expand2( + [top.poly], + -offset1, + -offsetN, + -offset1, + top.traces, + count, + function(polys, countNow) { + last = polys; + // mark each poly with depth (offset #) starting at 0 + polys.forEach(function(p) { + p.depth = count - countNow; + if (p.inner) p.inner.forEach(function(pi) { + // use negative offset for inners + pi.depth = -(count - countNow); + }); + }); + }, + top.poly.getZ()); + } else { + POLY.expand( + [top.poly], + -offset1, + top.poly.getZ(), + top.traces, + count, + -offsetN, + function(polys, countNow) { + last = polys; + // mark each poly with depth (offset #) starting at 0 + polys.forEach(function(p) { + p.depth = count - countNow; + if (p.inner) p.inner.forEach(function(pi) { + // use negative offset for inners + pi.depth = -(count - countNow); + }); + }); }); - }); - }); + } } } diff --git a/js/kiri.js b/js/kiri.js index 861ae011..33c8c8f0 100644 --- a/js/kiri.js +++ b/js/kiri.js @@ -82,6 +82,7 @@ self.kiri.license = exports.LICENSE; outputFinishFactor: 1, outputAccelComp: 1, outputOuterFirst: 1, + detectThinWalls: 1, outputWipeSpeed: 1, outputWipeDistance: 1, outputClockwise: 1, @@ -281,6 +282,7 @@ self.kiri.license = exports.LICENSE; outputFinishFactor: 0, outputAccelComp: false, outputOuterFirst: false, + detectThinWalls: false, // --- LASER --- @@ -2369,6 +2371,7 @@ self.kiri.license = exports.LICENSE; outputFinishFactor: UC.newInput("finish factor", {title:"% of nozzle diameter to\nshorten finish path by\nvalues of 0-1", bound:UC.bound(0.0,1), convert:UC.toFloat, modes:FDM}), outputAccelComp: UC.newBoolean("acceleration", onBooleanClick, {title: "acceleration compensation\nexperimental", modes:FDM}), outputOuterFirst: UC.newBoolean("outer first", onBooleanClick, {title: "output outermost shell first", modes:FDM}), + detectThinWalls: UC.newBoolean("thin wall", onBooleanClick, {title: "thin wall detection\nexperimental", modes:FDM}), }); function toolUpdate(a,b,c) {