diff --git a/release.md b/release.md index b8244c3d..ec01a9b3 100644 --- a/release.md +++ b/release.md @@ -3,7 +3,7 @@ Full docs @ https://docs.grid.space/projects/kiri-moto -# Release 3.8 +# Release 3.8 (2023-01-21) * update server-side sample module code * various fixes and improvements to CAM indexing @@ -23,6 +23,7 @@ Full docs @ https://docs.grid.space/projects/kiri-moto * CAM fix tracing nested polyline offset ordering * CAM refactor of contouring yields 2x - 20x speedup * CAM update traces to async slicing, fix use with flip +* CAM add threading support for all slicing ops - refactor object/group storage model in Mesh:Tool - add omit pocket to rough and outline @@ -85,6 +86,7 @@ Full docs @ https://docs.grid.space/projects/kiri-moto * add CAM Z bottom inversion option to flip operator * add CAM custom gcode operator (can be used for pausing, too) * add CAM z extend option on registration op independent of "Z Thru" global +* add CAM pocket surface selection filter by angle * add optional CAM operation notes (helps with many similar ops) * add option to limit CAM trace ops to Z bottom limit (when in use) * extend url loading of workspaces to all formats diff --git a/src/kiri-mode/cam/client.js b/src/kiri-mode/cam/client.js index 259d4646..d397fddf 100644 --- a/src/kiri-mode/cam/client.js +++ b/src/kiri-mode/cam/client.js @@ -844,6 +844,7 @@ CAM.init = function(kiri, api) { func.clearPops(); alert = api.show.alert("analyzing surfaces...", 1000); let surfaces = poppedRec.surfaces; + let radians = poppedRec.follow * DEG2RAD; CAM.surface_prep(currentIndex * RAD2DEG, () => { api.hide.alert(alert); alert = api.show.alert("[esc] cancels surface editing"); @@ -851,7 +852,7 @@ CAM.init = function(kiri, api) { let widget = api.widgets.forid(wid); if (widget && arr.length) for (let faceid of arr) { - CAM.surface_toggle(widget, faceid, faceids => { + CAM.surface_toggle(widget, faceid, radians, faceids => { // surfaces[widget.id] = faceids; }); } @@ -864,7 +865,7 @@ CAM.init = function(kiri, api) { let min = Math.min(face.a, face.b, face.c); let faceid = min / 3; let widget = lastWidget = obj.object.widget; - CAM.surface_toggle(widget, faceid, faceids => { + CAM.surface_toggle(widget, faceid, radians, faceids => { surfaces[widget.id] = faceids; }); }; @@ -1338,10 +1339,11 @@ CAM.init = function(kiri, api) { plunge: 'camPocketPlunge', expand: 'camPocketExpand', smooth: 'camPocketSmooth', - refine: 'cmaPocketRefine', + refine: 'camPocketRefine', + follow: 'camPocketFollow', contour: 'camPocketContour', engrave: 'camPocketEngrave', - outline: 'cmaPocketOutline', + outline: 'camPocketOutline', tolerance: 'camTolerance', }).inputs = { tool: UC.newSelect(LANG.cc_tool, {}, "tools"), @@ -1354,8 +1356,9 @@ CAM.init = function(kiri, api) { sep: UC.newBlank({class:"pop-sep"}), expand: UC.newInput(LANG.cp_xpnd_s, {title:LANG.cp_xpnd_l, convert:UC.toFloat, units:true, show:() => !poppedRec.contour}), refine: UC.newInput(LANG.cp_refi_s, {title:LANG.cp_refi_l, convert:UC.toInt, show:() => poppedRec.contour}), - smooth: UC.newInput(LANG.cp_smoo_s, {title:LANG.cp_smoo_l, convert:UC.toFloat, units:true}), + smooth: UC.newInput(LANG.cp_smoo_s, {title:LANG.cp_smoo_l, convert:UC.toInt}), tolerance: UC.newInput(LANG.ou_toll_s, {title:LANG.ou_toll_l, convert:UC.toFloat, bound:UC.bound(0,10.0), units:true, round:4, show:() => poppedRec.contour}), + follow: UC.newInput(LANG.cp_foll_s, {title:LANG.cp_foll_l, convert:UC.toFloat}), 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}), diff --git a/src/kiri-mode/cam/driver.js b/src/kiri-mode/cam/driver.js index e2de2b28..0ffb20d9 100644 --- a/src/kiri-mode/cam/driver.js +++ b/src/kiri-mode/cam/driver.js @@ -37,7 +37,7 @@ kiri.load(api => { widget.selectFaces(Object.values(widget._surfaces).flat()); }; - CAM.surface_toggle = function(widget, face, ondone) { + CAM.surface_toggle = function(widget, face, radians, ondone) { let surfaces = widget._surfaces = widget._surfaces || {}; for (let [root, faces] of Object.entries(surfaces)) { if (faces.contains(face)) { @@ -48,7 +48,7 @@ kiri.load(api => { return; } } - kiri.client.send("cam_surface_find", { id: widget.id, face }, faces => { + kiri.client.send("cam_surface_find", { id: widget.id, face, radians }, faces => { if (faces.length) { surfaces[face] = faces; CAM.surface_show(widget); @@ -92,9 +92,9 @@ kiri.load(api => { } }; - CAM.surface_find = function(widget, faces) { + CAM.surface_find = function(widget, faces, radians) { CAM.surface_prep(widget); - return widget.tool.findConnectedSurface(faces, 0.1, 0.0); + return widget.tool.findConnectedSurface(faces, radians || 0, 0.0); }; kiri.worker.cam_surfaces = function(data, send) { @@ -114,9 +114,9 @@ kiri.load(api => { }; kiri.worker.cam_surface_find = function(data, send) { - const { id, face } = data; + const { id, face, radians } = data; const widget = kiri.worker.cache[id]; - const faces = CAM.surface_find(widget, [face]); + const faces = CAM.surface_find(widget, [face], radians); send.done(faces); } diff --git a/src/kiri-mode/cam/ops.js b/src/kiri-mode/cam/ops.js index 503c9077..bfae9a34 100644 --- a/src/kiri-mode/cam/ops.js +++ b/src/kiri-mode/cam/ops.js @@ -1054,7 +1054,9 @@ class OpPocket extends CamOp { onupdate: (index, total, msg) => { progress((index / total) * 0.9, msg); }, - ondone: (slices) => { }, + ondone: (slices) => { + // console.log({ contour: slices }); + }, contour: { tool, tolerance, diff --git a/src/kiri-mode/cam/slice.js b/src/kiri-mode/cam/slice.js index 8fddcc70..973364f1 100644 --- a/src/kiri-mode/cam/slice.js +++ b/src/kiri-mode/cam/slice.js @@ -333,13 +333,13 @@ CAM.traces = async function(settings, widget, single) { let slicer = new kiri.cam_slicer(widget); let indices = [...new Set(Object.keys(slicer.zFlat) .map(kv => parseFloat(kv).round(5)) - .appendAll(Object.entries(slicer.zLine).map(ze => { - let [ zk, zv ] = ze; - return zv > 1 ? parseFloat(zk).round(5) : null; - }) - .filter(v => v !== null)))] + // .appendAll(Object.entries(slicer.zLine).map(ze => { + // let [ zk, zv ] = ze; + // return zv > 1 ? parseFloat(zk).round(5) : null; + // }) + // .filter(v => v !== null)) + )] .sort((a,b) => b - a); - let traces = []; // find and trim polys (including open) to shadow let oneach = data => { @@ -369,8 +369,9 @@ CAM.traces = async function(settings, widget, single) { traces.push(poly); }); }; - let opts = { each: oneach, over: false, flatoff: 0, edges: true, openok: true }; + let opts = { each: oneach, over: false, flatoff: 0, edges: true, openok: true, lines: true }; await slicer.slice(indices, opts); + // pick up bottom features opts.over = true; await slicer.slice(indices, opts); widget.traces = traces; diff --git a/src/kiri-mode/cam/slicer.js b/src/kiri-mode/cam/slicer.js index 7e5dbd43..fa0eec39 100644 --- a/src/kiri-mode/cam/slicer.js +++ b/src/kiri-mode/cam/slicer.js @@ -10,7 +10,7 @@ gapp.register("kiri-mode.cam.slicer", [], (root, exports) => { const { base, kiri } = root; -const { config, util, polygons, newOrderedLine, newPoint } = base; +const { config, util, polygons, newOrderedLine, newPoint, newLine } = base; const { sliceConnect, sliceDedup } = base; const { newSlice } = kiri; @@ -237,18 +237,27 @@ class Slicer { } async sliceBucketMinion(bucket, opt, oneach) { + const { decode, decodePointArray } = kiri.codec; const slices = (await new Promise(resolve => { kiri.minions.queue({ cmd: "cam_slice", - opt: { lines: false }, + opt: Object.clone(opt), bucket, }, resolve); })).slices; for (let slice of slices) { + slice.polys = decode(slice.polys); + if (slice.lines) { + slice.lines = decodePointArray(slice.lines) + .group(2) + .map(arr => { + return newLine(arr[0], arr[1]) + }); + } oneach(slice); } // console.log(bucket, slices); - return kiri.codec.decode(slices); + return slices; } async sliceBucket(bucket, opt, oneach) { @@ -472,10 +481,19 @@ moto.broker.subscribe("minion.started", msg => { funcs.cam_slice = (data, seq) => { const { bucket, opt } = data; + const { encode, encodePointArray } = kiri.codec; + // log({ slice: bucket, opt }); cache.slicer.sliceBucket(bucket, opt, slice => { // console.log({ slice }); }).then(data => { - reply({ seq, slices: kiri.codec.encode(data) }); + data.forEach(rec => { + rec.polys = encode(rec.polys); + if (rec.lines) { + const points = rec.lines.map(l => [l.p1, l.p2]).flat(); + rec.lines = encodePointArray(points); + } + }); + reply({ seq, slices: data }); }); }; }); diff --git a/src/kiri-mode/cam/topo.js b/src/kiri-mode/cam/topo.js index afe59da5..41569523 100644 --- a/src/kiri-mode/cam/topo.js +++ b/src/kiri-mode/cam/topo.js @@ -119,6 +119,8 @@ class Topo { stepsY, boundsX, boundsY, + minX, + minY, zMin }); @@ -311,6 +313,10 @@ class Topo { stepsTotal += ((maxX - minX + partOff * 2) / toolStep) | 0; } + if (stepsTotal === 0) { + return; + } + const box = params.box.clone().expandByVector(new THREE.Vector3( partOff, partOff, 0 )); @@ -411,7 +417,7 @@ class Probe { constructor(params) { const { data, profile } = params; - const { stepsX, stepsY, boundsX, boundsY, zMin } = params; + const { stepsX, stepsY, boundsX, boundsY, zMin, minX, minY } = params; this.params = params; diff --git a/src/kiri/conf.js b/src/kiri/conf.js index be753879..1979990b 100644 --- a/src/kiri/conf.js +++ b/src/kiri/conf.js @@ -514,10 +514,11 @@ const conf = exports({ camPocketPlunge: 200, camPocketExpand: 0, camPocketSmooth: 0, - cmaPocketRefine: 20, + camPocketRefine: 20, + camPocketFollow: 5, camPocketContour: false, camPocketEngrave: false, - cmaPocketOutline: false, + camPocketOutline: false, camDrillTool: 1000, camDrillSpindle: 1000, camDrillDownSpeed: 250, diff --git a/web/kiri/lang/en.js b/web/kiri/lang/en.js index 7e854563..78c550b9 100644 --- a/web/kiri/lang/en.js +++ b/web/kiri/lang/en.js @@ -527,6 +527,8 @@ self.kiri.lang['en-us'] = { cp_xpnd_l: ["grow selected area to","encompass corners"], cp_smoo_s: "smooth", cp_smoo_l: ["clean up jagged edges caused by angled walls. can speedup and improve pocketing for detailed geometries. recommend starting with values around 1 if slicing takes too long or the contours look jagged"], + cp_foll_s: "selection", + cp_foll_l: ["curvature selection limit in degrees. values closer to 0 will restrict selections to flatter surfaces"], cp_refi_s: "refine", cp_refi_l: ["number of refining passes to perform on contoured polylines. meant to address Z delta sawtoothing caused by faced geometries whereas smoothing handles XY. values > 10 work well for gently contoured geometries with significant Z movement."], cp_cont_s: "contour",