diff --git a/notes.md b/notes.md index 7487d10f..dcb07bca 100644 --- a/notes.md +++ b/notes.md @@ -59,6 +59,7 @@ * `B` outside cutting direction in roughing mode inverted * `B` on rotation, tabs dissociate from parts whose center changes with rotation +* `F` clip-to option under "stock" * `F` add climb/conventional into each operation * `F` new registration style: offset cutout * `F` z thru should apply to any thru hole diff --git a/src/geo/polygon.js b/src/geo/polygon.js index 68dd21fa..402ad5bd 100644 --- a/src/geo/polygon.js +++ b/src/geo/polygon.js @@ -1440,7 +1440,7 @@ } }; - PRO.cut = function(polys) { + PRO.cut = function(polys, inter) { let target = this; if (!target.open) { @@ -1460,13 +1460,14 @@ cfil = clib.PolyFillType, clip = new clib.Clipper(), ctre = new clib.PolyTree(), + type = inter ? ctyp.ctIntersection : ctyp.ctDifference, sp1 = target.toClipper(), sp2 = POLY().toClipper(polys); clip.AddPaths(sp1, ptyp.ptSubject, false); clip.AddPaths(sp2, ptyp.ptClip, true); - if (clip.Execute(ctyp.ctDifference, ctre, cfil.pftEvenOdd, cfil.pftEvenOdd)) { + if (clip.Execute(type, ctre, cfil.pftEvenOdd, cfil.pftEvenOdd)) { let cuts = POLY().fromClipperTree(ctre, target.getZ(), null, null, 0); cuts.forEach(no => { // heal open but really closed polygons because cutting diff --git a/src/kiri/conf.js b/src/kiri/conf.js index fa40e946..16b974f1 100644 --- a/src/kiri/conf.js +++ b/src/kiri/conf.js @@ -479,6 +479,7 @@ camStockY: 5, camStockZ: 0, camStockOffset: true, + camStockClipTo: false, camStockOn: true, camConventional: false, // outputClockwise outputOriginCenter: false, diff --git a/src/kiri/init.js b/src/kiri/init.js index 991aa25f..5877a0b4 100644 --- a/src/kiri/init.js +++ b/src/kiri/init.js @@ -1649,6 +1649,7 @@ camStockY: UC.newInput(LANG.cs_dpth_s, {title:LANG.cs_dpth_l, convert:UC.toFloat, bound:UC.bound(0,9999), modes:CAM, units:true}), camStockZ: UC.newInput(LANG.cs_hght_s, {title:LANG.cs_hght_l, convert:UC.toFloat, bound:UC.bound(0,9999), modes:CAM, units:true}), camStockOffset: UC.newBoolean(LANG.cs_offs_s, onBooleanClick, {title:LANG.cs_offs_l, modes:CAM}), + camStockClipTo: UC.newBoolean(LANG.cs_clip_s, onBooleanClick, {title:LANG.cs_clip_l, modes:CAM}), camSep: UC.newBlank({class:"pop-sep"}), camStockOn: UC.newBoolean(LANG.cs_offe_s, onBooleanClick, {title:LANG.cs_offe_l, modes:CAM}), diff --git a/src/mode/cam/ops.js b/src/mode/cam/ops.js index 0b86498e..555ca279 100644 --- a/src/mode/cam/ops.js +++ b/src/mode/cam/ops.js @@ -105,8 +105,9 @@ slice(progress) { let { op, state } = this; let { settings, widget, slicer, sliceAll, unsafe } = state; - let { updateToolDiams, thruHoles, tabs, cutTabs } = state; + let { updateToolDiams, thruHoles, tabs, cutTabs, cutPolys } = state; let { tshadow, shadowTop, ztOff, zBottom, zMax } = state; + let { process, stock } = settings; let roughIn = op.inside; let roughTop = op.top; @@ -261,6 +262,11 @@ if (!offset) return; + if (process.camStockClipTo) { + let rect = newPolygon().centerRectangle(stock.center, stock.x, stock.y); + offset = cutPolys([rect], offset, slice.z, true); + } + // elimate double inset on inners offset.forEach(op => { if (op.inner) { @@ -376,7 +382,8 @@ slice(progress) { let { op, state } = this; let { settings, widget, slicer, sliceAll, tshadow, thruHoles, unsafe } = state; - let { updateToolDiams, zThru, zBottom, shadowTop, tabs, cutTabs } = state; + let { updateToolDiams, zThru, zBottom, shadowTop, tabs, cutTabs, cutPolys } = state; + let { process, stock } = settings; let toolDiam = this.toolDiam = new CAM.Tool(settings, op.tool).fluteDiameter(); updateToolDiams(toolDiam); @@ -497,6 +504,11 @@ CAM.addDogbones(offset, toolDiam / 5); } + if (process.camStockClipTo) { + let rect = newPolygon().centerRectangle(stock.center, stock.x, stock.y); + offset = cutPolys([rect], offset, slice.z, true); + } + // offset.xout(`slice ${slice.z}`); slice.camLines = offset; if (false) slice.output() diff --git a/src/mode/cam/slice.js b/src/mode/cam/slice.js index a4bc7e47..2b98f4a1 100644 --- a/src/mode/cam/slice.js +++ b/src/mode/cam/slice.js @@ -105,6 +105,7 @@ bounds, tabs, cutTabs, + cutPolys, slicer, sliceAll, updateToolDiams, @@ -265,10 +266,15 @@ return true; }; - function cutTabs(tabs, offset, z) { - let noff = []; + function cutTabs(tabs, offset, z, inter) { tabs = tabs.filter(tab => z < tab.pos.z + tab.dim.z/2).map(tab => tab.off).flat(); - offset.forEach(op => noff.appendAll( op.cut(POLY.union(tabs, 0, true)) )); + return cutPolys(tabs, offset, z, false); + } + + function cutPolys(polys, offset, z, inter) { + let noff = []; + // tabs = tabs.filter(tab => z < tab.pos.z + tab.dim.z/2).map(tab => tab.off).flat(); + offset.forEach(op => noff.appendAll( op.cut(POLY.union(polys, 0, true), inter) )); if (noff.length > 1) { let heal = 0; // heal/rejoin open segments that share endpoints diff --git a/web/kiri/lang/en.js b/web/kiri/lang/en.js index e5e22e62..242fe579 100644 --- a/web/kiri/lang/en.js +++ b/web/kiri/lang/en.js @@ -435,6 +435,8 @@ kiri.lang['en-us'] = { cs_hght_l: "height (z) in workspace units\n0 defaults to part size", cs_offs_s: "offset", cs_offs_l: "use width, depth, height\nas offsets from max\npart size on platform", + cs_clip_s: "clip to", + cs_clip_l: "rough and outline\nclip cutting paths\nto defined stock", cs_offe_s: "enable", cs_offe_l: "enable milling stock",