From d88a484560afda0078dfe2ef1f0e03abb9666047 Mon Sep 17 00:00:00 2001 From: bakedpotatolord Date: Sat, 24 May 2025 13:02:33 -0600 Subject: [PATCH 01/11] make bounding recs 0-based --- src/kiri-mode/cam/ops.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kiri-mode/cam/ops.js b/src/kiri-mode/cam/ops.js index e87fb5e4..dced8347 100644 --- a/src/kiri-mode/cam/ops.js +++ b/src/kiri-mode/cam/ops.js @@ -657,7 +657,7 @@ class OpOutline extends CamOp { } if (process.camStockClipTo && stock.x && stock.y && stock.center) { - let rect = newPolygon().centerRectangle(stock.center, stock.x, stock.y); + let rect = newPolygon().centerRectangle({x:0,y:0}, stock.x, stock.y); offset = cutPolys([rect], offset, slice.z, true); } @@ -1000,7 +1000,7 @@ class OpTrace extends CamOp { let cutdir = ov_conv; let polys = []; let stockRect = stock.center && stock.x && stock.y ? - newPolygon().centerRectangle(stock.center, stock.x, stock.y) : undefined; + newPolygon().centerRectangle({x:0,y:0}, stock.x, stock.y) : undefined; updateToolDiams(toolDiam); if (tabs) { From fdc61bd09adef17d53861b336496bf379022bb62 Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Sun, 25 May 2025 18:39:22 -0600 Subject: [PATCH 02/11] update widget outline when rotated or scaled --- src/kiri/widget.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/kiri/widget.js b/src/kiri/widget.js index bad76c24..d66f6607 100644 --- a/src/kiri/widget.js +++ b/src/kiri/widget.js @@ -545,6 +545,9 @@ class Widget { this.setWireframe(false); this.clearSlices(); mesh.geometry.applyMatrix4(new THREE.Matrix4().makeScale(x, y, z)); + if (this.outline) { + this.setEdges(true); + } scale.x *= (x || 1.0); scale.y *= (y || 1.0); scale.z *= (z || 1.0); @@ -558,6 +561,9 @@ class Widget { if (center) { this.center(false); } + if (this.outline) { + this.setEdges(true); + } if ((x || y || z) && api && api.event) { api.event.emit('widget.rotate', {widget: this, x, y, z}); } From 4593efd8ea04511b28b2bf4ff3b914cf76fcdbf8 Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Sun, 25 May 2025 18:45:57 -0600 Subject: [PATCH 03/11] fix disabling index op --- src/kiri-mode/cam/client.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/kiri-mode/cam/client.js b/src/kiri-mode/cam/client.js index 4b1bf706..46bab9d5 100644 --- a/src/kiri-mode/cam/client.js +++ b/src/kiri-mode/cam/client.js @@ -479,7 +479,7 @@ CAM.init = function(kiri, api) { if (op.type === '|') { break; } - if (op.type === 'index') { + if (op.type === 'index' && !op.disabled) { indexing = true; if (op.absolute) { index = op.degrees @@ -641,6 +641,9 @@ CAM.init = function(kiri, api) { el.classList.remove("disabled"); } } + if (isIndexed) { + updateIndex(); + } return true; } // duplicate op From b6573a49906927e55647629556095332b44b34e6 Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Mon, 26 May 2025 17:33:12 -0600 Subject: [PATCH 04/11] allow recompute of workspace units in op chains. fix bounding box changes in indexed op chains --- src/kiri-mode/cam/slice.js | 111 +++++++++++++++++++------------------ src/kiri/widget.js | 5 +- 2 files changed, 60 insertions(+), 56 deletions(-) diff --git a/src/kiri-mode/cam/slice.js b/src/kiri-mode/cam/slice.js index aae4bfac..aab397a4 100644 --- a/src/kiri-mode/cam/slice.js +++ b/src/kiri-mode/cam/slice.js @@ -30,66 +30,68 @@ const POLY = polygons; */ CAM.slice = async function(settings, widget, onupdate, ondone) { let proc = settings.process, - stock = settings.stock || {}, - isIndexed = proc.camStockIndexed, - camOps = widget.camops = [], sliceAll = widget.slices = [], - bounds = widget.getBoundingBox(), - track = widget.track, - { camZTop, camZBottom, camZThru } = proc, - // widget top z as defined by setTopz() - wztop = track.top, - // distance between top of part and top of stock - ztOff = isIndexed ? 0 : (stock.z - wztop), - // distance between bottom of part and bottom of stock - zbOff = isIndexed ? 0 : (wztop - track.box.d), - // defined z bottom offset by distance to stock bottom - // keeps the z bottom relative to the part when z align changes - zBottom = isIndexed ? camZBottom : camZBottom - zbOff, - // greater of widget bottom and z bottom - zMin = isIndexed ? bounds.min.z : Math.max(bounds.min.z, zBottom), - zMax = bounds.max.z, - zThru = camZThru, - zTop = zMax + ztOff, - minToolDiam = Infinity, - maxToolDiam = -Infinity, - dark = settings.controller.dark ? true : false, - color = dark ? 0xbbbbbb : 0, - tabs = widget.anno.tab, - unsafe = proc.camExpertFast, - units = settings.controller.units === 'in' ? 25.4 : 1, - axisRotation, - axisIndex, - // new work area tracking - part_size = bounds.dim, - bottom_gap = zbOff, - bottom_part = 0, - bottom_stock = -bottom_gap, - bottom_thru = zThru, + // slices = widget.slices = [], + camOps = widget.camops = [], + isIndexed = proc.camStockIndexed; + + let stock, bounds, track, + camZTop, camZBottom, camZThru, wztop, ztOff, zbOff, + zBottom, zMin, zMax, zThru, zTop, + minToolDiam, maxToolDiam, dark, color, tabs, unsafe, units, + axisRotation, axisIndex, + part_size, + bottom_gap, bottom_part, bottom_stock, bottom_thru, bottom_z, bottom_cut, + top_stock, top_part, top_gap, top_z, + workarea; + + // allow recomputing later if widget or settings changes + const var_compute = () => { + stock = settings.stock || {}; + bounds = widget.getBoundingBox(); + track = widget.track; + ({ camZTop, camZBottom, camZThru } = proc); + wztop = track.top; + ztOff = isIndexed ? 0 : (stock.z - wztop); + zbOff = isIndexed ? 0 : (wztop - track.box.d); + zBottom = isIndexed ? camZBottom : camZBottom - zbOff; + zMin = isIndexed ? bounds.min.z : Math.max(bounds.min.z, zBottom); + zMax = bounds.max.z; + zThru = camZThru; + zTop = zMax + ztOff; + minToolDiam = Infinity; + maxToolDiam = -Infinity; + dark = !!settings.controller.dark; + color = dark ? 0xbbbbbb : 0; + tabs = widget.anno.tab; + unsafe = proc.camExpertFast; + units = settings.controller.units === 'in' ? 25.4 : 1; + axisRotation = axisIndex = undefined; + part_size = bounds.dim; + bottom_gap = zbOff; + bottom_part = 0; + bottom_stock = -bottom_gap; + bottom_thru = zThru; bottom_z = Math.max( (camZBottom ? bottom_stock + camZBottom : bottom_part) - bottom_thru, (camZBottom ? bottom_stock + camZBottom : bottom_stock - bottom_thru) - ), - bottom_cut = Math.max(bottom_z, -zThru), - top_stock = zTop, - top_part = zMax, - top_gap = ztOff, - top_z = camZTop ? bottom_stock + camZTop : top_stock, + ); + bottom_cut = Math.max(bottom_z, -zThru); + top_stock = zTop; + top_part = zMax; + top_gap = ztOff; + top_z = camZTop ? bottom_stock + camZTop : top_stock; workarea = util.round({ - top_stock, - top_part, - top_gap, - top_z, - bottom_stock, - bottom_part, - bottom_gap, - bottom_z, - bottom_cut + top_stock, top_part, top_gap, top_z, + bottom_stock, bottom_part, bottom_gap, + bottom_z, bottom_cut }, 3); - // console.table({ workarea }); - // console.table({ part_size }); - // console.table({ stock }); + return structuredClone(workarea); + }; + + // initial setup + var_compute(); if (tabs) { // make tab polygons @@ -267,12 +269,11 @@ CAM.slice = async function(settings, widget, onupdate, ondone) { // call slice() function on all ops in order let tracker = setSliceTracker({ rotation: 0 }); - let workarea_orig = structuredClone(workarea); setAxisIndex(); for (let op of opList) { let weight = op.weight(); // apply operation override vars - let workover = structuredClone(workarea_orig); + let workover = var_compute(); let valz = op.op; if (valz.ov_topz) { workover.top_z = bottom_stock + valz.ov_topz; diff --git a/src/kiri/widget.js b/src/kiri/widget.js index d66f6607..61eb8ddf 100644 --- a/src/kiri/widget.js +++ b/src/kiri/widget.js @@ -704,7 +704,10 @@ class Widget { getBoundingBox(refresh) { if (!this.bounds || refresh || this.boundingBoxNeedsUpdate) { - this.bounds = new THREE.Box3().setFromArray(this.getGeoVertices()); + this.bounds = new THREE.Box3().setFromArray(this.getGeoVertices({ + translate: true, + unroll: false + })); this.boundingBoxNeedsUpdate = false; } return this.bounds; From 950331740bf5aa59062762c9a234eb14639872c1 Mon Sep 17 00:00:00 2001 From: bakedpotatolord Date: Tue, 27 May 2025 10:02:17 -0600 Subject: [PATCH 05/11] fix analysing parts alert --- src/kiri-mode/cam/client.js | 13 +++++++++---- src/kiri-mode/cam/driver.js | 15 +++++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/kiri-mode/cam/client.js b/src/kiri-mode/cam/client.js index 46bab9d5..d83d4897 100644 --- a/src/kiri-mode/cam/client.js +++ b/src/kiri-mode/cam/client.js @@ -1184,7 +1184,7 @@ CAM.init = function(kiri, api) { return func.selectHolesDone(); } func.clearPops(); - alert = api.show.alert("analyzing parts...", 1000); + let alert = api.show.alert("analyzing parts..."); holeSelOn = hoveredOp; holeSelOn.classList.add("editing"); api.feature.hover = true; @@ -1225,6 +1225,7 @@ CAM.init = function(kiri, api) { let meshesCached = widgets.every(widget=>poppedRec.drills[widget.id] != undefined) if( individual && meshesCached ){ // if any widget already has cached holes // console.log("already has cached holes",poppedRec.drills) + api.hide.alert(alert) kiri.api.widgets.for(widget => { if(widget.adds){ let drills = poppedRec.drills[widget.id] @@ -1245,8 +1246,9 @@ CAM.init = function(kiri, api) { }) }else{ // if no widget has cached holes - await CAM.holes(individual?0:diam,(centers)=>{ + await CAM.holes( individual ? 0 : diam, async centers => { let shadow = centers.some(c=>c.shadowed) + api.hide.alert(alert) if(shadow){ alert = api.show.alert("Some holes are shadowed by part and are not shown."); } @@ -1270,8 +1272,11 @@ CAM.init = function(kiri, api) { }); } //hide the alert once hole meshes are calculated on the worker, and then added to the scene - api.hide.alert(alert); - alert = api.show.alert("[esc] cancels drill editing"); + // api.hide.alert(alert); + let escAlert = api.show.alert("[esc] cancels drill editing",1000); + setTimeout(() => { + api.hide.alert(escAlert); + }, 5000); kiri.api.widgets.opacity(0.8); } diff --git a/src/kiri-mode/cam/driver.js b/src/kiri-mode/cam/driver.js index 12882077..9b1970ad 100644 --- a/src/kiri-mode/cam/driver.js +++ b/src/kiri-mode/cam/driver.js @@ -87,10 +87,17 @@ kiri.load(api => { kiri.client.sync(); const settings = api.conf.get(); const widgets = api.widgets.map(); - kiri.client.send("cam_holes", { settings, diam }, output => { - let res = kiri.codec.decode(output) - onDone(res) - }); + let prom = new Promise((res,rej)=>{ + + kiri.client.send("cam_holes", { settings, diam }, output => { + let out = kiri.codec.decode(output) + console.log(out) + onDone(out) + res(out) + }); + }) + + return prom } } From 212908ada5ffaea1b5ee6715f7adf923038d798a Mon Sep 17 00:00:00 2001 From: bakedpotatolord Date: Tue, 27 May 2025 11:19:51 -0600 Subject: [PATCH 06/11] add configurable precision for drill op --- src/kiri-mode/cam/client.js | 17 ++++++++--------- src/kiri-mode/cam/driver.js | 15 +++++---------- src/kiri-mode/cam/slice.js | 29 ++++++++++++++++------------- src/kiri/conf.js | 1 + web/kiri/lang/en.js | 2 ++ 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/kiri-mode/cam/client.js b/src/kiri-mode/cam/client.js index d83d4897..c9b05788 100644 --- a/src/kiri-mode/cam/client.js +++ b/src/kiri-mode/cam/client.js @@ -1192,9 +1192,7 @@ CAM.init = function(kiri, api) { func.hover = func.selectHolesHover; func.hoverUp = func.selectHolesHoverUp; - let settings = API.conf.get(); - const {tool,mark} = poppedRec //TODO: display some visual difference if mark is selected - let diam = new CAM.Tool(settings,tool).fluteDiameter() + const widgets = kiri.api.widgets.all() @@ -1205,7 +1203,7 @@ CAM.init = function(kiri, api) { * @returns {Mesh} the created mesh */ function createHoleMesh(widget,drill){ - let {depth,selected} = drill + let {depth,selected, diam} = drill let color = selected ? 0xFF0000:0x39e366 let geo = new THREE.CylinderGeometry(diam/2,diam/2,depth,20); const material = new THREE.MeshPhongMaterial( { color } ); @@ -1246,7 +1244,7 @@ CAM.init = function(kiri, api) { }) }else{ // if no widget has cached holes - await CAM.holes( individual ? 0 : diam, async centers => { + await CAM.holes( individual,poppedRec, async centers => { let shadow = centers.some(c=>c.shadowed) api.hide.alert(alert) if(shadow){ @@ -1787,10 +1785,10 @@ CAM.init = function(kiri, api) { dwell: 'camDrillDwell', lift: 'camDrillLift', mark: 'camDrillMark', + precision:'camDrillPrecision', thru: 'camDrillThru', - }) - drillOp.inputs = { + }).inputs = { tool: UC.newSelect(LANG.cc_tool, {}, "tools"), sep: UC.newBlank({class:"pop-sep"}), spindle: UC.newInput(LANG.cc_spnd_s, {title:LANG.cc_spnd_l, convert:UC.toInt, show:hasSpindle}), @@ -1800,8 +1798,9 @@ CAM.init = function(kiri, api) { lift: UC.newInput(LANG.cd_lift_s, {title:LANG.cd_lift_l, convert:UC.toFloat, units:true, show:() => !poppedRec.mark}), mark: UC.newBoolean(LANG.cd_mark_s, undefined, {title:LANG.cd_mark_l}), sep: UC.newBlank({class:"pop-sep"}), - thru: UC.newInput(LANG.cd_dtru_s, {title:LANG.cd_dtru_l, convert:UC.toFloat, units:true}), - sep: UC.newBlank({class:"pop-sep"}), + thru: UC.newInput(LANG.cd_dtru_s, {title:LANG.cd_dtru_l, convert:UC.toFloat, units:true,show:() => !poppedRec.mark}), + precision:UC.newInput(LANG.cd_prcn_s, {title:LANG.cd_prcn_l, convert:UC.toFloat, units:true,show:() => !poppedRec.mark}), + sep: UC.newBlank({class:"pop-sep", }), actions: UC.newRow([ UC.newButton(LANG.select, ()=>func.selectHoles(true), {title:LANG.cd_seli_l}), UC.newButton(LANG.cd_sela_s, ()=>func.selectHoles(false), {title:LANG.cd_sela_l}) diff --git a/src/kiri-mode/cam/driver.js b/src/kiri-mode/cam/driver.js index 9b1970ad..a12e8c53 100644 --- a/src/kiri-mode/cam/driver.js +++ b/src/kiri-mode/cam/driver.js @@ -83,21 +83,16 @@ kiri.load(api => { }; //0 or less diameter means select all holes - CAM.holes = function(diam,onDone) { + CAM.holes = function(indiv,rec,onDone) { kiri.client.sync(); const settings = api.conf.get(); - const widgets = api.widgets.map(); - let prom = new Promise((res,rej)=>{ - - kiri.client.send("cam_holes", { settings, diam }, output => { + return new Promise((res,rej)=>{ + kiri.client.send("cam_holes", { settings, rec, indiv }, output => { let out = kiri.codec.decode(output) - console.log(out) onDone(out) res(out) }); }) - - return prom } } @@ -163,11 +158,11 @@ kiri.load(api => { }; kiri.worker.cam_holes = async function(data, send) { - const { settings, diam } = data; + const { settings, indiv, rec } = data; const widgets = Object.values(kiri.worker.cache); const fresh = []; for (let widget of widgets) { - if (await CAM.holes(settings, widget, diam)) { + if (await CAM.holes(settings, widget, indiv, rec)) { fresh.push(widget); } } diff --git a/src/kiri-mode/cam/slice.js b/src/kiri-mode/cam/slice.js index aab397a4..5e835067 100644 --- a/src/kiri-mode/cam/slice.js +++ b/src/kiri-mode/cam/slice.js @@ -444,7 +444,11 @@ CAM.traces = async function(settings, widget, single) { * @param {number} diam - diameter of the drill bit * @returns {Array} list of hole centers as objects with `x`, `y`, `z`, `depth`, and `selected` properties. */ -CAM.holes = async function(settings, widget, diam) { +CAM.holes = async function(settings, widget, individual, rec) { + + let {tool,mark,precision} = rec //TODO: display some visual difference if mark is selected + let toolDiam = new CAM.Tool(settings,tool).fluteDiameter() + let diam = individual ? 1 : toolDiam; // sets default diameter when select individual used let proc = settings.process, stock = settings.stock || {}, @@ -462,23 +466,23 @@ CAM.holes = async function(settings, widget, diam) { zBottom = isIndexed ? camZBottom : camZBottom - zbOff; - let slicerOpts = {flatoff: 0.01} + let slicerOpts = {flatoff: 0.001} let slicer = new kiri.cam_slicer(widget,slicerOpts); - let zFlats = Object.keys(slicer.zFlat).map(Number).map(z=>[z]).flat() + let zFlats = Object.keys(slicer.zFlat).map(Number).map(z=>[z,z-0.002]).flat() - let intervals = slicer.interval(1,{ - fit: false, off: -0.01, flats: true - }) + precision = Math.max( 0, precision ) + let intervals = (precision == 0) ? [] : slicer.interval( + precision, + { + fit: false, off: -0.01, flats: true + } + ) let zees = [...zFlats,...intervals] let indices = [...new Set(zees .map(kv => parseFloat(kv).round(5)) .filter(z => z !== null) )] - let individual = (diam <= 0); - - diam = individual ? 1 : diam; // sets default diameter when select individual used - let centerDiff = diam * 0.1, area = (diam/2) * (diam/2) * Math.PI, circles = [], @@ -494,7 +498,7 @@ CAM.holes = async function(settings, widget, diam) { for (let slice of slices) { for(let top of slice.tops){ // console.log("slicing",slice.z,top) - slice.shadow = CAM.shadowAt(widget,slice.z, 0) + slice.shadow = CAM.shadowAt(widget, slice.z, 0) let inner = top.inner; if (!inner) { //no holes continue; @@ -537,7 +541,6 @@ CAM.holes = async function(settings, widget, diam) { for (let c of circles) { let overlapping = c.overlapping - .sort((a,b) => b.z - a.z) let last = overlapping.shift(); while (overlapping.length) { @@ -555,9 +558,9 @@ CAM.holes = async function(settings, widget, diam) { } if (last.depth != 0) drills.push(last) //add last circle } - drills.forEach( h=>{ delete h.overlapping //for encoding + h.diam = toolDiam // for mesh generation h.selected = (!individual && Math.abs(h.area - area) <= area * 0.05 ); //for same size selection }) diff --git a/src/kiri/conf.js b/src/kiri/conf.js index ea61c40a..1830281f 100644 --- a/src/kiri/conf.js +++ b/src/kiri/conf.js @@ -521,6 +521,7 @@ const conf = exports({ camDrillLift: 2, camDrillMark: false, camDrillThru: 5, + camDrillPrecision: 1, camDrillingOn: false, camRegisterSpeed: 1000, camRegisterThru: 5, diff --git a/web/kiri/lang/en.js b/web/kiri/lang/en.js index 9061c291..72a84134 100644 --- a/web/kiri/lang/en.js +++ b/web/kiri/lang/en.js @@ -599,6 +599,8 @@ self.kiri.lang['en-us'] = { cd_dtru_l: ["additional drill depth below part bottom","overrides global z thru","0 to disable"], cd_mark_s: "marking", cd_mark_l: ["only mark holes, do not drill out","the step down setting is used","to determine how deep to mark"], + cd_prcn_s: "precision", + cd_prcn_l: ["distance between slices","to search for holes","in workspace units","lower is slower and","uses more memory","0 = only flats"], cd_seli_l: ["individually select holes","to drill"], cd_sela_s: "Select Matching Diameter", From 38622b40d9f55baa587b7692d2b0d8d0c0f61c34 Mon Sep 17 00:00:00 2001 From: bakedpotatolord Date: Sat, 31 May 2025 09:25:38 -0600 Subject: [PATCH 07/11] fix drill bug --- src/kiri-mode/cam/slice.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kiri-mode/cam/slice.js b/src/kiri-mode/cam/slice.js index aab397a4..0d1a80e9 100644 --- a/src/kiri-mode/cam/slice.js +++ b/src/kiri-mode/cam/slice.js @@ -500,6 +500,7 @@ CAM.holes = async function(settings, widget, diam) { continue; } for (let poly of inner) { + if ( poly.points.length < 7 ) continue; let center = poly.calcCircleCenter(); center.area = poly.area(); center.overlapping = [center] From 45823642c3c0f962f1d0493d3a2c7fb0b9c580f6 Mon Sep 17 00:00:00 2001 From: bakedpotatolord Date: Sat, 31 May 2025 18:52:07 -0600 Subject: [PATCH 08/11] remove dead whitespace --- src/kiri-mode/cam/ops.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/kiri-mode/cam/ops.js b/src/kiri-mode/cam/ops.js index dced8347..7df5ac1b 100644 --- a/src/kiri-mode/cam/ops.js +++ b/src/kiri-mode/cam/ops.js @@ -1503,22 +1503,19 @@ class OpDrill extends CamOp { if(!drill.selected){ return } - let slice = newSlice(0); + let slice = newSlice(0); if (op.mark) { // replace depth with single down peck drill.depth = op.down } drill.zBottom = drill.z - drill.depth; - // for thru holes, follow z thru when set if ((op.thru>0) ) { drill.zBottom -= op.thru; } - const poly = newPolygon() poly.points.push(newPoint(drill.x, drill.y, drill.z)) poly.points.push(newPoint(drill.x, drill.y, drill.zBottom)) - // poly.points.pop(); slice.camTrace = { tool: op.tool, rate: op.feed, plunge: op.rate }; slice.camLines = [poly]; From f2d6120a5fc4c1b4a85b1b1e1120aa35c9fe65e4 Mon Sep 17 00:00:00 2001 From: bakedpotatolord Date: Sat, 31 May 2025 20:03:56 -0600 Subject: [PATCH 09/11] add prettier config --- prettier.config.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 prettier.config.js diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 00000000..5a5bf0eb --- /dev/null +++ b/prettier.config.js @@ -0,0 +1,19 @@ + +/** + * @see https://prettier.io/docs/configuration + * @type {import("prettier").Config} + */ +const config = { + trailingComma: "es5", + useTabs: false, + bracketSpacing: true, + objectWrap: "preserve", + tabWidth: 4, + semi: false, + singleQuote: true, + bracketSameLine: true, + arrowParens: "always", + endOfLine: "crlf" +} + +module.exports = config \ No newline at end of file From 079bf039122c68da39c87a33937b21f2677a75be Mon Sep 17 00:00:00 2001 From: bakedpotatolord Date: Sat, 31 May 2025 22:21:55 -0600 Subject: [PATCH 10/11] add progress bar for cam holes --- src/kiri-mode/cam/client.js | 63 +++++++++++++++++++++++-------------- src/kiri-mode/cam/driver.js | 21 +++++++++---- src/kiri-mode/cam/slice.js | 14 ++++++--- src/kiri-mode/cam/slicer.js | 14 ++++++++- src/kiri/alerts.js | 1 + 5 files changed, 77 insertions(+), 36 deletions(-) diff --git a/src/kiri-mode/cam/client.js b/src/kiri-mode/cam/client.js index c9b05788..d5b201d5 100644 --- a/src/kiri-mode/cam/client.js +++ b/src/kiri-mode/cam/client.js @@ -1219,7 +1219,6 @@ CAM.init = function(kiri, api) { widget.adds.push(mesh); //for click detection return mesh } - let meshesCached = widgets.every(widget=>poppedRec.drills[widget.id] != undefined) if( individual && meshesCached ){ // if any widget already has cached holes // console.log("already has cached holes",poppedRec.drills) @@ -1244,30 +1243,46 @@ CAM.init = function(kiri, api) { }) }else{ // if no widget has cached holes - await CAM.holes( individual,poppedRec, async centers => { - let shadow = centers.some(c=>c.shadowed) - api.hide.alert(alert) - if(shadow){ - alert = api.show.alert("Some holes are shadowed by part and are not shown."); - } - centers = centers ?? [] - // list of all hole centers and if they are selected - kiri.api.widgets.for(widget => { - const {holes} = centers.find(center=>center.id = widget.id) - // console.log(holes) - if (!holes.length) unselectHoles(holes); - holes.forEach(hole => { - createHoleMesh(widget, hole) + let alert = api.show.alert(""); + await CAM.holes( + individual, + poppedRec, + (progress,msg)=>{ + console.log(progress,msg) + alert[0]=msg + api.show.progress(progress,msg) + api.alerts.update() + }, + async centers => { + api.show.progress(0) + if(! Array.isArray(centers) ){ + console.log("worker returned a malformed drills response") + return + } + let shadow = centers.some(c=>c.shadowed) + api.hide.alert(alert) + if(shadow){ + alert = api.show.alert("Some holes are shadowed by part and are not shown."); + } + centers = centers ?? [] + // list of all hole centers and if they are selected + kiri.api.widgets.for(widget => { + const {holes} = centers.find(center=>center.id = widget.id) + // console.log(holes) + if (!holes.length) unselectHoles(holes); + holes.forEach(hole => { + createHoleMesh(widget, hole) + }) + //add hole data to record + poppedRec.drills = poppedRec.drills ?? {} + poppedRec.drills[widget.id] = holes + //give widget access to an array of drill records that refrence it + //so that it can be cleared when widget is rotated or mirrored etc. + if(!widget.drills){widget.drills = []} + widget.drills.push(holes) }) - //add hole data to record - poppedRec.drills = poppedRec.drills ?? {} - poppedRec.drills[widget.id] = holes - //give widget access to an array of drill records that refrence it - //so that it can be cleared when widget is rotated or mirrored etc. - if(!widget.drills){widget.drills = []} - widget.drills.push(holes) - }) - }); + } + ); } //hide the alert once hole meshes are calculated on the worker, and then added to the scene // api.hide.alert(alert); diff --git a/src/kiri-mode/cam/driver.js b/src/kiri-mode/cam/driver.js index a12e8c53..44220e29 100644 --- a/src/kiri-mode/cam/driver.js +++ b/src/kiri-mode/cam/driver.js @@ -82,15 +82,21 @@ kiri.load(api => { }); }; - //0 or less diameter means select all holes - CAM.holes = function(indiv,rec,onDone) { + + CAM.holes = function(indiv,rec,onProgress,onDone) { kiri.client.sync(); const settings = api.conf.get(); return new Promise((res,rej)=>{ kiri.client.send("cam_holes", { settings, rec, indiv }, output => { let out = kiri.codec.decode(output) - onDone(out) - res(out) + if(out.progress != undefined){ + //if a progress message, + onProgress(out.progress,out.msg) + }else{ + api.hide.alert(alert) + onDone(out) + res(out) + } }); }) } @@ -161,8 +167,11 @@ kiri.load(api => { const { settings, indiv, rec } = data; const widgets = Object.values(kiri.worker.cache); const fresh = []; - for (let widget of widgets) { - if (await CAM.holes(settings, widget, indiv, rec)) { + + for (let [i,widget] of widgets.entries() ) { + if (await CAM.holes(settings, widget, indiv, rec, + ( prog, msg )=>{ send.data({progress: (i/widgets.length)+(prog/widgets.length),msg})} + )){ fresh.push(widget); } } diff --git a/src/kiri-mode/cam/slice.js b/src/kiri-mode/cam/slice.js index 93a1d396..9f0db31a 100644 --- a/src/kiri-mode/cam/slice.js +++ b/src/kiri-mode/cam/slice.js @@ -441,10 +441,12 @@ CAM.traces = async function(settings, widget, single) { * * @param {Object} settings - settings object * @param {Object} widget - widget object - * @param {number} diam - diameter of the drill bit + * @param {boolean} individual - if true, drill holes individually + * @param {Object} rec - DrillOp record + * @param {Function} onProgress - callback function to report progress * @returns {Array} list of hole centers as objects with `x`, `y`, `z`, `depth`, and `selected` properties. */ -CAM.holes = async function(settings, widget, individual, rec) { +CAM.holes = async function(settings, widget, individual, rec,onProgress) { let {tool,mark,precision} = rec //TODO: display some visual difference if mark is selected let toolDiam = new CAM.Tool(settings,tool).fluteDiameter() @@ -491,11 +493,11 @@ CAM.holes = async function(settings, widget, individual, rec) { function onEach(slice) { slices.push(slice); } - let opts = { each: onEach }; + let opts = { each: onEach, progress: (num,total)=> onProgress(num/total*0.5,"slice") }; await slicer.slice(indices, opts); let shadowedDrills = false; // console.log("slices",slices) - for (let slice of slices) { + for (let [i,slice] of slices.entries()) { for(let top of slice.tops){ // console.log("slicing",slice.z,top) slice.shadow = CAM.shadowAt(widget, slice.z, 0) @@ -536,11 +538,12 @@ CAM.holes = async function(settings, widget, individual, rec) { if (!overlap) circles.push(center); } } + onProgress(0.5+(i/slices.length*0.25),"recognize circles") } let drills = [] - for (let c of circles) { + for (let [i,c] of circles.entries()) { let overlapping = c.overlapping let last = overlapping.shift(); @@ -558,6 +561,7 @@ CAM.holes = async function(settings, widget, individual, rec) { } } if (last.depth != 0) drills.push(last) //add last circle + onProgress(0.75+(i/circles.length*0.25),"assemble holes") } drills.forEach( h=>{ delete h.overlapping //for encoding diff --git a/src/kiri-mode/cam/slicer.js b/src/kiri-mode/cam/slicer.js index 5bc28ade..ab4b4317 100644 --- a/src/kiri-mode/cam/slicer.js +++ b/src/kiri-mode/cam/slicer.js @@ -135,9 +135,21 @@ class Slicer { return this; } - // slice through points at given Z and return polygons + /** + * Given an array of z-slice positions, generate a list of polygons + * representing the intersection of the mesh with the given z-slice + * positions. + * + * @param {number[]} zs - array of z-slice positions + * @param {Object} options - slicing parameters + * @param {number} [options.flatoff=0.01] - z offset when slicing on a flat surface + * @param {boolean} [options.progress=false] - callback with slice progress + * @param {function} [options.each] - callback with each slice result + * @returns {Promise} - list of slice objects with z and tops (polygons) + */ async slice(zs, options) { const opt = this.setOptions(options); + // slice through points at given Z and return polygons if (!Array.isArray(zs)) { throw "slice zs parameter must be ab array"; diff --git a/src/kiri/alerts.js b/src/kiri/alerts.js index de674953..8ed32689 100644 --- a/src/kiri/alerts.js +++ b/src/kiri/alerts.js @@ -19,6 +19,7 @@ function show(message, time) { api.event.emit('alert', rec); } else { alerts.push(rec); + setTimeout( update, time+0.02); update(); } return rec; From 9d9b70efa8d46210bb0bbb214e67d85967fdb598 Mon Sep 17 00:00:00 2001 From: bakedpotatolord Date: Sat, 31 May 2025 22:27:04 -0600 Subject: [PATCH 11/11] remove console log --- src/kiri-mode/cam/client.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/kiri-mode/cam/client.js b/src/kiri-mode/cam/client.js index d5b201d5..94b44438 100644 --- a/src/kiri-mode/cam/client.js +++ b/src/kiri-mode/cam/client.js @@ -1248,7 +1248,6 @@ CAM.init = function(kiri, api) { individual, poppedRec, (progress,msg)=>{ - console.log(progress,msg) alert[0]=msg api.show.progress(progress,msg) api.alerts.update()