From 56e4206930b0b83c7c1817b202041ad05ed52e20 Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Mon, 10 Oct 2022 00:00:08 -0400 Subject: [PATCH] checkpoint cam pocket contour setup --- release.md | 2 ++ src/geo/polygon.js | 41 +++++++++++++++++++++++++++++++- src/kiri-mode/cam/client.js | 10 ++++++-- src/kiri-mode/cam/ops.js | 47 ++++++++++++++++++++++++++++--------- src/kiri/conf.js | 2 ++ web/kiri/lang/en.js | 4 ++++ 6 files changed, 92 insertions(+), 14 deletions(-) diff --git a/release.md b/release.md index 1216fdc0..ceecde54 100644 --- a/release.md +++ b/release.md @@ -7,6 +7,8 @@ Full docs @ https://docs.grid.space/projects/kiri-moto * improve CAM animation speeds * add CAM op level part offset parameters for xy and z +* add CAM pocket smoothing and contouring which is closer to true 3 axis +* fix CAM invalidation of tabs on scale and traces on scale or rotate * fix belt fan override for base extrusions touching belt # Release 3.5 (2022-10-07) diff --git a/src/geo/polygon.js b/src/geo/polygon.js index 54bc35d9..2f71074c 100644 --- a/src/geo/polygon.js +++ b/src/geo/polygon.js @@ -1629,6 +1629,8 @@ class Polygon { } } + // cut poly using array of closed polygons. used primarily in cnc + // to cut perimeters using tabs resulting in open poly lines. cut(polys, inter) { let target = this; @@ -1670,7 +1672,7 @@ class Polygon { } } - + // find the intersection of two polygons intersect(poly, min) { if (!this.overlaps(poly)) return null; @@ -1793,6 +1795,7 @@ class Polygon { return this; } + // turn 2d polygon into closed 3d mesh faces extrude(z = 1) { let poly = this.clone().setClockwise(); let faces = []; @@ -1810,6 +1813,42 @@ class Polygon { } return faces; } + + // split long straight lines into segments no longer than max + // and return a new polygon + segment(max = 1) { + const newp = []; + const points = this.points; + const length = points.length; + for (let i=0, p=points, l1=length, l2=l1+1; i length) { + return newPolygon().addPoints(newp.map(p => p.clone())); + } + return this; + } + } // use Slope.angleDiff() then re-test path mitering / rendering diff --git a/src/kiri-mode/cam/client.js b/src/kiri-mode/cam/client.js index 9e41dd72..6b39c8ea 100644 --- a/src/kiri-mode/cam/client.js +++ b/src/kiri-mode/cam/client.js @@ -151,6 +151,7 @@ CAM.init = function(kiri, api) { "selection.scale", "selection.rotate" ], () => { + if (!isCamMode) return; for (let op of current.process.ops) { if (op.type === 'trace') { op.areas = {}; @@ -1140,6 +1141,8 @@ CAM.init = function(kiri, api) { rate: 'camPocketSpeed', plunge: 'camPocketPlunge', expand: 'camPocketExpand', + smooth: 'camPocketSmooth', + contour: 'camPocketContour', outline: 'cmaPocketOutline' }).inputs = { tool: UC.newSelect(LANG.cc_tool, {}, "tools"), @@ -1150,8 +1153,11 @@ CAM.init = function(kiri, api) { rate: UC.newInput(LANG.cc_feed_s, {title:LANG.cc_feed_l, convert:UC.toInt, units:true}), plunge: UC.newInput(LANG.cc_plng_s, {title:LANG.cc_plng_l, convert:UC.toInt, units:true}), sep: UC.newBlank({class:"pop-sep"}), - expand: UC.newInput(LANG.cp_xpnd_s, {title:LANG.cp_xpnd_l, convert:UC.toFloat, units:true}), - outline: UC.newBoolean(LANG.cp_outl_s, undefined, {title:LANG.cp_outl_l}), + expand: UC.newInput(LANG.cp_xpnd_s, {title:LANG.cp_xpnd_l, convert:UC.toFloat, units:true, show:() => !poppedRec.contour}), + smooth: UC.newInput(LANG.cp_smoo_s, {title:LANG.cp_smoo_l, convert:UC.toFloat, units:true}), + sep: UC.newBlank({class:"pop-sep"}), + contour: UC.newBoolean(LANG.cp_cont_s, undefined, {title:LANG.cp_cont_s}), + outline: UC.newBoolean(LANG.cp_outl_s, undefined, {title:LANG.cp_outl_l, show:() => !poppedRec.contour}), sep: UC.newBlank({class:"pop-sep"}), menu: UC.newRow([ UC.newButton(undefined, func.surfaceAdd, {icon:''}), diff --git a/src/kiri-mode/cam/ops.js b/src/kiri-mode/cam/ops.js index 03ca7b1d..5810d4d9 100644 --- a/src/kiri-mode/cam/ops.js +++ b/src/kiri-mode/cam/ops.js @@ -957,8 +957,9 @@ class OpPocket extends CamOp { } slice(progress) { + const debug = true; let { op, state } = this; - let { tool, rate, down, plunge, expand } = op; + let { tool, rate, down, plunge, expand, contour, smooth } = op; let { settings, widget, sliceAll, zMax, zTop, zThru, tabs, color } = state; let { updateToolDiams, cutTabs, cutPolys, healPolys, shadowAt } = state; let { process, stock } = settings; @@ -967,6 +968,9 @@ class OpPocket extends CamOp { let toolDiam = new CAM.Tool(settings, tool).fluteDiameter(); let toolOver = toolDiam * op.step; let cutdir = process.camConventional; + if (contour) { + down = 0; + } updateToolDiams(toolDiam); if (tabs) { tabs.forEach(tab => { @@ -987,13 +991,32 @@ class OpPocket extends CamOp { down = diff / Math.ceil(diff / down); } let zs = down ? base.util.lerp(zTop, z, down) : [ z ]; - if (expand) polys = POLY.offset(polys, expand); - let zpro = 0, zinc = 1 / (polys.length * zs.length); + if (contour) { + expand = toolOver; + } + if (expand) { + polys = POLY.offset(polys, expand); + } + let zpro = 0, zinc = 1 / (polys.length * zs.length); for (let poly of polys) { for (let z of zs) { - let shadow = shadowAt(z); - let clip = []; - POLY.subtract([ poly ], shadow, clip); + let clip = [], shadow; + if (contour) { + if (smooth) { + clip = POLY.offset(POLY.offset([ poly ], smooth), -smooth); + } else { + clip = [ poly ]; + } + } else { + shadow = shadowAt(z); + if (smooth) { + shadow = POLY.offset(POLY.offset(shadow, smooth), -smooth); + } + POLY.subtract([ poly ], shadow, clip); + } + if (clip.length === 0) { + continue; + } let slice = newSliceOut(z); slice.camTrace = { tool, rate, plunge }; POLY.offset(clip, [ -toolDiam / 2, -toolOver ], { @@ -1008,7 +1031,7 @@ class OpPocket extends CamOp { slice.output() .setLayer("pocket", {line: color}, false) .addPolys(slice.camLines) - if (false) slice.output() + if (debug && shadow) slice.output() .setLayer("pocket shadow", {line: 0xff8811}, false) .addPolys(shadow) progress(zpro += zinc, "pocket"); @@ -1032,15 +1055,17 @@ class OpPocket extends CamOp { outline = POLY.union(outline, 0.0001, true); outline = POLY.setWinding(outline, cutdir, false); outline = healPolys(outline); - let pinc = 1; + if (smooth) { + outline = POLY.offset(POLY.offset(outline, smooth), -smooth); + } if (outline.length) { // option to skip interior features (holes, pillars) - if (op.outline) { + if (!contour && op.outline) { for (let p of outline) { p.inner = undefined; } } - if (false) newSliceOut(zmin).output() + if (debug) newSliceOut(zmin).output() .setLayer("pocket area", {line: 0x1188ff}, false) .addPolys(outline) clearZ(outline, zmin + 0.0001, down); @@ -1055,7 +1080,7 @@ class OpPocket extends CamOp { setTool(op.tool, op.rate); setSpindle(op.spindle); let i=0, l=sliceOut.length; - for (let slice of sliceOut) { + for (let slice of sliceOut.filter(s => s.camLines)) { ops.emitTrace(slice); progress(++i / l, "pocket"); } diff --git a/src/kiri/conf.js b/src/kiri/conf.js index b7b8dec5..166ae687 100644 --- a/src/kiri/conf.js +++ b/src/kiri/conf.js @@ -509,6 +509,8 @@ const conf = exports({ camPocketSpeed: 250, camPocketPlunge: 200, camPocketExpand: 0, + camPocketSmooth: 0, + camPocketContour: false, cmaPocketOutline: false, camDrillTool: 1000, camDrillSpindle: 1000, diff --git a/web/kiri/lang/en.js b/web/kiri/lang/en.js index b382f14e..984d38f3 100644 --- a/web/kiri/lang/en.js +++ b/web/kiri/lang/en.js @@ -515,6 +515,10 @@ self.kiri.lang['en-us'] = { // CNC POCKET cp_xpnd_s: "expand", cp_xpnd_l: ["grow selected area to","encompass corners"], + cp_smoo_s: "smooth", + cp_smoo_l: ["clean up jagged edges caused by highly angled walls. can speedup pocketing for detailed geometries. recommend a value around 1"], + cp_cont_s: "contour", + cp_cont_l: ["ignore interior voids and features"], cp_outl_s: "outline only", cp_outl_l: ["ignore interior voids and features"],