Merge branch 'rel-4.1' of https://github.com/GridSpace/grid-apps into cam-arcs
This commit is contained in:
commit
3ffc3ab853
10 changed files with 207 additions and 125 deletions
19
prettier.config.js
Normal file
19
prettier.config.js
Normal file
|
|
@ -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
|
||||||
|
|
@ -479,7 +479,7 @@ CAM.init = function(kiri, api) {
|
||||||
if (op.type === '|') {
|
if (op.type === '|') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (op.type === 'index') {
|
if (op.type === 'index' && !op.disabled) {
|
||||||
indexing = true;
|
indexing = true;
|
||||||
if (op.absolute) {
|
if (op.absolute) {
|
||||||
index = op.degrees
|
index = op.degrees
|
||||||
|
|
@ -641,6 +641,9 @@ CAM.init = function(kiri, api) {
|
||||||
el.classList.remove("disabled");
|
el.classList.remove("disabled");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isIndexed) {
|
||||||
|
updateIndex();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// duplicate op
|
// duplicate op
|
||||||
|
|
@ -1181,7 +1184,7 @@ CAM.init = function(kiri, api) {
|
||||||
return func.selectHolesDone();
|
return func.selectHolesDone();
|
||||||
}
|
}
|
||||||
func.clearPops();
|
func.clearPops();
|
||||||
alert = api.show.alert("analyzing parts...", 1000);
|
let alert = api.show.alert("analyzing parts...");
|
||||||
holeSelOn = hoveredOp;
|
holeSelOn = hoveredOp;
|
||||||
holeSelOn.classList.add("editing");
|
holeSelOn.classList.add("editing");
|
||||||
api.feature.hover = true;
|
api.feature.hover = true;
|
||||||
|
|
@ -1189,9 +1192,7 @@ CAM.init = function(kiri, api) {
|
||||||
func.hover = func.selectHolesHover;
|
func.hover = func.selectHolesHover;
|
||||||
func.hoverUp = func.selectHolesHoverUp;
|
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()
|
const widgets = kiri.api.widgets.all()
|
||||||
|
|
@ -1202,7 +1203,7 @@ CAM.init = function(kiri, api) {
|
||||||
* @returns {Mesh} the created mesh
|
* @returns {Mesh} the created mesh
|
||||||
*/
|
*/
|
||||||
function createHoleMesh(widget,drill){
|
function createHoleMesh(widget,drill){
|
||||||
let {depth,selected} = drill
|
let {depth,selected, diam} = drill
|
||||||
let color = selected ? 0xFF0000:0x39e366
|
let color = selected ? 0xFF0000:0x39e366
|
||||||
let geo = new THREE.CylinderGeometry(diam/2,diam/2,depth,20);
|
let geo = new THREE.CylinderGeometry(diam/2,diam/2,depth,20);
|
||||||
const material = new THREE.MeshPhongMaterial( { color } );
|
const material = new THREE.MeshPhongMaterial( { color } );
|
||||||
|
|
@ -1218,10 +1219,10 @@ CAM.init = function(kiri, api) {
|
||||||
widget.adds.push(mesh); //for click detection
|
widget.adds.push(mesh); //for click detection
|
||||||
return mesh
|
return mesh
|
||||||
}
|
}
|
||||||
|
|
||||||
let meshesCached = widgets.every(widget=>poppedRec.drills[widget.id] != undefined)
|
let meshesCached = widgets.every(widget=>poppedRec.drills[widget.id] != undefined)
|
||||||
if( individual && meshesCached ){ // if any widget already has cached holes
|
if( individual && meshesCached ){ // if any widget already has cached holes
|
||||||
// console.log("already has cached holes",poppedRec.drills)
|
// console.log("already has cached holes",poppedRec.drills)
|
||||||
|
api.hide.alert(alert)
|
||||||
kiri.api.widgets.for(widget => {
|
kiri.api.widgets.for(widget => {
|
||||||
if(widget.adds){
|
if(widget.adds){
|
||||||
let drills = poppedRec.drills[widget.id]
|
let drills = poppedRec.drills[widget.id]
|
||||||
|
|
@ -1242,33 +1243,52 @@ CAM.init = function(kiri, api) {
|
||||||
})
|
})
|
||||||
|
|
||||||
}else{ // if no widget has cached holes
|
}else{ // if no widget has cached holes
|
||||||
await CAM.holes(individual?0:diam,(centers)=>{
|
let alert = api.show.alert("");
|
||||||
let shadow = centers.some(c=>c.shadowed)
|
await CAM.holes(
|
||||||
if(shadow){
|
individual,
|
||||||
alert = api.show.alert("Some holes are shadowed by part and are not shown.");
|
poppedRec,
|
||||||
}
|
(progress,msg)=>{
|
||||||
centers = centers ?? []
|
alert[0]=msg
|
||||||
// list of all hole centers and if they are selected
|
api.show.progress(progress,msg)
|
||||||
kiri.api.widgets.for(widget => {
|
api.alerts.update()
|
||||||
const {holes} = centers.find(center=>center.id = widget.id)
|
},
|
||||||
// console.log(holes)
|
async centers => {
|
||||||
if (!holes.length) unselectHoles(holes);
|
api.show.progress(0)
|
||||||
holes.forEach(hole => {
|
if(! Array.isArray(centers) ){
|
||||||
createHoleMesh(widget, hole)
|
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
|
//hide the alert once hole meshes are calculated on the worker, and then added to the scene
|
||||||
api.hide.alert(alert);
|
// api.hide.alert(alert);
|
||||||
alert = api.show.alert("[esc] cancels drill editing");
|
let escAlert = api.show.alert("[esc] cancels drill editing",1000);
|
||||||
|
setTimeout(() => {
|
||||||
|
api.hide.alert(escAlert);
|
||||||
|
}, 5000);
|
||||||
kiri.api.widgets.opacity(0.8);
|
kiri.api.widgets.opacity(0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1779,10 +1799,10 @@ CAM.init = function(kiri, api) {
|
||||||
dwell: 'camDrillDwell',
|
dwell: 'camDrillDwell',
|
||||||
lift: 'camDrillLift',
|
lift: 'camDrillLift',
|
||||||
mark: 'camDrillMark',
|
mark: 'camDrillMark',
|
||||||
|
precision:'camDrillPrecision',
|
||||||
thru: 'camDrillThru',
|
thru: 'camDrillThru',
|
||||||
|
|
||||||
})
|
}).inputs = {
|
||||||
drillOp.inputs = {
|
|
||||||
tool: UC.newSelect(LANG.cc_tool, {}, "tools"),
|
tool: UC.newSelect(LANG.cc_tool, {}, "tools"),
|
||||||
sep: UC.newBlank({class:"pop-sep"}),
|
sep: UC.newBlank({class:"pop-sep"}),
|
||||||
spindle: UC.newInput(LANG.cc_spnd_s, {title:LANG.cc_spnd_l, convert:UC.toInt, show:hasSpindle}),
|
spindle: UC.newInput(LANG.cc_spnd_s, {title:LANG.cc_spnd_l, convert:UC.toInt, show:hasSpindle}),
|
||||||
|
|
@ -1792,8 +1812,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}),
|
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}),
|
mark: UC.newBoolean(LANG.cd_mark_s, undefined, {title:LANG.cd_mark_l}),
|
||||||
sep: UC.newBlank({class:"pop-sep"}),
|
sep: UC.newBlank({class:"pop-sep"}),
|
||||||
thru: UC.newInput(LANG.cd_dtru_s, {title:LANG.cd_dtru_l, convert:UC.toFloat, units:true}),
|
thru: UC.newInput(LANG.cd_dtru_s, {title:LANG.cd_dtru_l, convert:UC.toFloat, units:true,show:() => !poppedRec.mark}),
|
||||||
sep: UC.newBlank({class:"pop-sep"}),
|
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([
|
actions: UC.newRow([
|
||||||
UC.newButton(LANG.select, ()=>func.selectHoles(true), {title:LANG.cd_seli_l}),
|
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})
|
UC.newButton(LANG.cd_sela_s, ()=>func.selectHoles(false), {title:LANG.cd_sela_l})
|
||||||
|
|
|
||||||
|
|
@ -82,15 +82,23 @@ kiri.load(api => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
//0 or less diameter means select all holes
|
|
||||||
CAM.holes = function(diam,onDone) {
|
CAM.holes = function(indiv,rec,onProgress,onDone) {
|
||||||
kiri.client.sync();
|
kiri.client.sync();
|
||||||
const settings = api.conf.get();
|
const settings = api.conf.get();
|
||||||
const widgets = api.widgets.map();
|
return new Promise((res,rej)=>{
|
||||||
kiri.client.send("cam_holes", { settings, diam }, output => {
|
kiri.client.send("cam_holes", { settings, rec, indiv }, output => {
|
||||||
let res = kiri.codec.decode(output)
|
let out = kiri.codec.decode(output)
|
||||||
onDone(res)
|
if(out.progress != undefined){
|
||||||
});
|
//if a progress message,
|
||||||
|
onProgress(out.progress,out.msg)
|
||||||
|
}else{
|
||||||
|
api.hide.alert(alert)
|
||||||
|
onDone(out)
|
||||||
|
res(out)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,11 +164,14 @@ kiri.load(api => {
|
||||||
};
|
};
|
||||||
|
|
||||||
kiri.worker.cam_holes = async function(data, send) {
|
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 widgets = Object.values(kiri.worker.cache);
|
||||||
const fresh = [];
|
const fresh = [];
|
||||||
for (let widget of widgets) {
|
|
||||||
if (await CAM.holes(settings, widget, diam)) {
|
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);
|
fresh.push(widget);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -657,7 +657,7 @@ class OpOutline extends CamOp {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.camStockClipTo && stock.x && stock.y && stock.center) {
|
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);
|
offset = cutPolys([rect], offset, slice.z, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1000,7 +1000,7 @@ class OpTrace extends CamOp {
|
||||||
let cutdir = ov_conv;
|
let cutdir = ov_conv;
|
||||||
let polys = [];
|
let polys = [];
|
||||||
let stockRect = stock.center && stock.x && stock.y ?
|
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);
|
updateToolDiams(toolDiam);
|
||||||
|
|
||||||
if (tabs) {
|
if (tabs) {
|
||||||
|
|
@ -1509,16 +1509,13 @@ class OpDrill extends CamOp {
|
||||||
drill.depth = op.down
|
drill.depth = op.down
|
||||||
}
|
}
|
||||||
drill.zBottom = drill.z - drill.depth;
|
drill.zBottom = drill.z - drill.depth;
|
||||||
|
|
||||||
// for thru holes, follow z thru when set
|
// for thru holes, follow z thru when set
|
||||||
if ((op.thru>0) ) {
|
if ((op.thru>0) ) {
|
||||||
drill.zBottom -= op.thru;
|
drill.zBottom -= op.thru;
|
||||||
}
|
}
|
||||||
|
|
||||||
const poly = newPolygon()
|
const poly = newPolygon()
|
||||||
poly.points.push(newPoint(drill.x, drill.y, drill.z))
|
poly.points.push(newPoint(drill.x, drill.y, drill.z))
|
||||||
poly.points.push(newPoint(drill.x, drill.y, drill.zBottom))
|
poly.points.push(newPoint(drill.x, drill.y, drill.zBottom))
|
||||||
|
|
||||||
// poly.points.pop();
|
// poly.points.pop();
|
||||||
slice.camTrace = { tool: op.tool, rate: op.feed, plunge: op.rate };
|
slice.camTrace = { tool: op.tool, rate: op.feed, plunge: op.rate };
|
||||||
slice.camLines = [poly];
|
slice.camLines = [poly];
|
||||||
|
|
|
||||||
|
|
@ -30,66 +30,68 @@ const POLY = polygons;
|
||||||
*/
|
*/
|
||||||
CAM.slice = async function(settings, widget, onupdate, ondone) {
|
CAM.slice = async function(settings, widget, onupdate, ondone) {
|
||||||
let proc = settings.process,
|
let proc = settings.process,
|
||||||
stock = settings.stock || {},
|
|
||||||
isIndexed = proc.camStockIndexed,
|
|
||||||
camOps = widget.camops = [],
|
|
||||||
sliceAll = widget.slices = [],
|
sliceAll = widget.slices = [],
|
||||||
bounds = widget.getBoundingBox(),
|
// slices = widget.slices = [],
|
||||||
track = widget.track,
|
camOps = widget.camops = [],
|
||||||
{ camZTop, camZBottom, camZThru } = proc,
|
isIndexed = proc.camStockIndexed;
|
||||||
// widget top z as defined by setTopz()
|
|
||||||
wztop = track.top,
|
let stock, bounds, track,
|
||||||
// distance between top of part and top of stock
|
camZTop, camZBottom, camZThru, wztop, ztOff, zbOff,
|
||||||
ztOff = isIndexed ? 0 : (stock.z - wztop),
|
zBottom, zMin, zMax, zThru, zTop,
|
||||||
// distance between bottom of part and bottom of stock
|
minToolDiam, maxToolDiam, dark, color, tabs, unsafe, units,
|
||||||
zbOff = isIndexed ? 0 : (wztop - track.box.d),
|
axisRotation, axisIndex,
|
||||||
// defined z bottom offset by distance to stock bottom
|
part_size,
|
||||||
// keeps the z bottom relative to the part when z align changes
|
bottom_gap, bottom_part, bottom_stock, bottom_thru, bottom_z, bottom_cut,
|
||||||
zBottom = isIndexed ? camZBottom : camZBottom - zbOff,
|
top_stock, top_part, top_gap, top_z,
|
||||||
// greater of widget bottom and z bottom
|
workarea;
|
||||||
zMin = isIndexed ? bounds.min.z : Math.max(bounds.min.z, zBottom),
|
|
||||||
zMax = bounds.max.z,
|
// allow recomputing later if widget or settings changes
|
||||||
zThru = camZThru,
|
const var_compute = () => {
|
||||||
zTop = zMax + ztOff,
|
stock = settings.stock || {};
|
||||||
minToolDiam = Infinity,
|
bounds = widget.getBoundingBox();
|
||||||
maxToolDiam = -Infinity,
|
track = widget.track;
|
||||||
dark = settings.controller.dark ? true : false,
|
({ camZTop, camZBottom, camZThru } = proc);
|
||||||
color = dark ? 0xbbbbbb : 0,
|
wztop = track.top;
|
||||||
tabs = widget.anno.tab,
|
ztOff = isIndexed ? 0 : (stock.z - wztop);
|
||||||
unsafe = proc.camExpertFast,
|
zbOff = isIndexed ? 0 : (wztop - track.box.d);
|
||||||
units = settings.controller.units === 'in' ? 25.4 : 1,
|
zBottom = isIndexed ? camZBottom : camZBottom - zbOff;
|
||||||
axisRotation,
|
zMin = isIndexed ? bounds.min.z : Math.max(bounds.min.z, zBottom);
|
||||||
axisIndex,
|
zMax = bounds.max.z;
|
||||||
// new work area tracking
|
zThru = camZThru;
|
||||||
part_size = bounds.dim,
|
zTop = zMax + ztOff;
|
||||||
bottom_gap = zbOff,
|
minToolDiam = Infinity;
|
||||||
bottom_part = 0,
|
maxToolDiam = -Infinity;
|
||||||
bottom_stock = -bottom_gap,
|
dark = !!settings.controller.dark;
|
||||||
bottom_thru = zThru,
|
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(
|
bottom_z = Math.max(
|
||||||
(camZBottom ? bottom_stock + camZBottom : bottom_part) - bottom_thru,
|
(camZBottom ? bottom_stock + camZBottom : bottom_part) - bottom_thru,
|
||||||
(camZBottom ? bottom_stock + camZBottom : bottom_stock - bottom_thru)
|
(camZBottom ? bottom_stock + camZBottom : bottom_stock - bottom_thru)
|
||||||
),
|
);
|
||||||
bottom_cut = Math.max(bottom_z, -zThru),
|
bottom_cut = Math.max(bottom_z, -zThru);
|
||||||
top_stock = zTop,
|
top_stock = zTop;
|
||||||
top_part = zMax,
|
top_part = zMax;
|
||||||
top_gap = ztOff,
|
top_gap = ztOff;
|
||||||
top_z = camZTop ? bottom_stock + camZTop : top_stock,
|
top_z = camZTop ? bottom_stock + camZTop : top_stock;
|
||||||
workarea = util.round({
|
workarea = util.round({
|
||||||
top_stock,
|
top_stock, top_part, top_gap, top_z,
|
||||||
top_part,
|
bottom_stock, bottom_part, bottom_gap,
|
||||||
top_gap,
|
bottom_z, bottom_cut
|
||||||
top_z,
|
|
||||||
bottom_stock,
|
|
||||||
bottom_part,
|
|
||||||
bottom_gap,
|
|
||||||
bottom_z,
|
|
||||||
bottom_cut
|
|
||||||
}, 3);
|
}, 3);
|
||||||
|
|
||||||
// console.table({ workarea });
|
return structuredClone(workarea);
|
||||||
// console.table({ part_size });
|
};
|
||||||
// console.table({ stock });
|
|
||||||
|
// initial setup
|
||||||
|
var_compute();
|
||||||
|
|
||||||
if (tabs) {
|
if (tabs) {
|
||||||
// make tab polygons
|
// make tab polygons
|
||||||
|
|
@ -267,12 +269,11 @@ CAM.slice = async function(settings, widget, onupdate, ondone) {
|
||||||
|
|
||||||
// call slice() function on all ops in order
|
// call slice() function on all ops in order
|
||||||
let tracker = setSliceTracker({ rotation: 0 });
|
let tracker = setSliceTracker({ rotation: 0 });
|
||||||
let workarea_orig = structuredClone(workarea);
|
|
||||||
setAxisIndex();
|
setAxisIndex();
|
||||||
for (let op of opList) {
|
for (let op of opList) {
|
||||||
let weight = op.weight();
|
let weight = op.weight();
|
||||||
// apply operation override vars
|
// apply operation override vars
|
||||||
let workover = structuredClone(workarea_orig);
|
let workover = var_compute();
|
||||||
let valz = op.op;
|
let valz = op.op;
|
||||||
if (valz.ov_topz) {
|
if (valz.ov_topz) {
|
||||||
workover.top_z = bottom_stock + valz.ov_topz;
|
workover.top_z = bottom_stock + valz.ov_topz;
|
||||||
|
|
@ -440,10 +441,16 @@ CAM.traces = async function(settings, widget, single) {
|
||||||
*
|
*
|
||||||
* @param {Object} settings - settings object
|
* @param {Object} settings - settings object
|
||||||
* @param {Object} widget - widget 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.
|
* @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,onProgress) {
|
||||||
|
|
||||||
|
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,
|
let proc = settings.process,
|
||||||
stock = settings.stock || {},
|
stock = settings.stock || {},
|
||||||
|
|
@ -461,23 +468,23 @@ CAM.holes = async function(settings, widget, diam) {
|
||||||
zBottom = isIndexed ? camZBottom : camZBottom - zbOff;
|
zBottom = isIndexed ? camZBottom : camZBottom - zbOff;
|
||||||
|
|
||||||
|
|
||||||
let slicerOpts = {flatoff: 0.01}
|
let slicerOpts = {flatoff: 0.001}
|
||||||
let slicer = new kiri.cam_slicer(widget,slicerOpts);
|
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,{
|
precision = Math.max( 0, precision )
|
||||||
fit: false, off: -0.01, flats: true
|
let intervals = (precision == 0) ? [] : slicer.interval(
|
||||||
})
|
precision,
|
||||||
|
{
|
||||||
|
fit: false, off: -0.01, flats: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
let zees = [...zFlats,...intervals]
|
let zees = [...zFlats,...intervals]
|
||||||
let indices = [...new Set(zees
|
let indices = [...new Set(zees
|
||||||
.map(kv => parseFloat(kv).round(5))
|
.map(kv => parseFloat(kv).round(5))
|
||||||
.filter(z => z !== null)
|
.filter(z => z !== null)
|
||||||
)]
|
)]
|
||||||
let individual = (diam <= 0);
|
|
||||||
|
|
||||||
diam = individual ? 1 : diam; // sets default diameter when select individual used
|
|
||||||
|
|
||||||
let centerDiff = diam * 0.1,
|
let centerDiff = diam * 0.1,
|
||||||
area = (diam/2) * (diam/2) * Math.PI,
|
area = (diam/2) * (diam/2) * Math.PI,
|
||||||
circles = [],
|
circles = [],
|
||||||
|
|
@ -486,19 +493,20 @@ CAM.holes = async function(settings, widget, diam) {
|
||||||
function onEach(slice) {
|
function onEach(slice) {
|
||||||
slices.push(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);
|
await slicer.slice(indices, opts);
|
||||||
let shadowedDrills = false;
|
let shadowedDrills = false;
|
||||||
// console.log("slices",slices)
|
// console.log("slices",slices)
|
||||||
for (let slice of slices) {
|
for (let [i,slice] of slices.entries()) {
|
||||||
for(let top of slice.tops){
|
for(let top of slice.tops){
|
||||||
// console.log("slicing",slice.z,top)
|
// 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;
|
let inner = top.inner;
|
||||||
if (!inner) { //no holes
|
if (!inner) { //no holes
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (let poly of inner) {
|
for (let poly of inner) {
|
||||||
|
if ( poly.points.length < 7 ) continue;
|
||||||
let center = poly.calcCircleCenter();
|
let center = poly.calcCircleCenter();
|
||||||
center.area = poly.area();
|
center.area = poly.area();
|
||||||
center.overlapping = [center]
|
center.overlapping = [center]
|
||||||
|
|
@ -530,13 +538,13 @@ CAM.holes = async function(settings, widget, diam) {
|
||||||
if (!overlap) circles.push(center);
|
if (!overlap) circles.push(center);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onProgress(0.5+(i/slices.length*0.25),"recognize circles")
|
||||||
}
|
}
|
||||||
|
|
||||||
let drills = []
|
let drills = []
|
||||||
|
|
||||||
for (let c of circles) {
|
for (let [i,c] of circles.entries()) {
|
||||||
let overlapping = c.overlapping
|
let overlapping = c.overlapping
|
||||||
.sort((a,b) => b.z - a.z)
|
|
||||||
|
|
||||||
let last = overlapping.shift();
|
let last = overlapping.shift();
|
||||||
while (overlapping.length) {
|
while (overlapping.length) {
|
||||||
|
|
@ -553,10 +561,11 @@ CAM.holes = async function(settings, widget, diam) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (last.depth != 0) drills.push(last) //add last circle
|
if (last.depth != 0) drills.push(last) //add last circle
|
||||||
|
onProgress(0.75+(i/circles.length*0.25),"assemble holes")
|
||||||
}
|
}
|
||||||
|
|
||||||
drills.forEach( h=>{
|
drills.forEach( h=>{
|
||||||
delete h.overlapping //for encoding
|
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
|
h.selected = (!individual && Math.abs(h.area - area) <= area * 0.05 ); //for same size selection
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -135,9 +135,21 @@ class Slicer {
|
||||||
return this;
|
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<Object[]>} - list of slice objects with z and tops (polygons)
|
||||||
|
*/
|
||||||
async slice(zs, options) {
|
async slice(zs, options) {
|
||||||
const opt = this.setOptions(options);
|
const opt = this.setOptions(options);
|
||||||
|
// slice through points at given Z and return polygons
|
||||||
|
|
||||||
if (!Array.isArray(zs)) {
|
if (!Array.isArray(zs)) {
|
||||||
throw "slice zs parameter must be ab array";
|
throw "slice zs parameter must be ab array";
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ function show(message, time) {
|
||||||
api.event.emit('alert', rec);
|
api.event.emit('alert', rec);
|
||||||
} else {
|
} else {
|
||||||
alerts.push(rec);
|
alerts.push(rec);
|
||||||
|
setTimeout( update, time+0.02);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
return rec;
|
return rec;
|
||||||
|
|
|
||||||
|
|
@ -521,6 +521,7 @@ const conf = exports({
|
||||||
camDrillLift: 2,
|
camDrillLift: 2,
|
||||||
camDrillMark: false,
|
camDrillMark: false,
|
||||||
camDrillThru: 5,
|
camDrillThru: 5,
|
||||||
|
camDrillPrecision: 1,
|
||||||
camDrillingOn: false,
|
camDrillingOn: false,
|
||||||
camRegisterSpeed: 1000,
|
camRegisterSpeed: 1000,
|
||||||
camRegisterThru: 5,
|
camRegisterThru: 5,
|
||||||
|
|
|
||||||
|
|
@ -545,6 +545,9 @@ class Widget {
|
||||||
this.setWireframe(false);
|
this.setWireframe(false);
|
||||||
this.clearSlices();
|
this.clearSlices();
|
||||||
mesh.geometry.applyMatrix4(new THREE.Matrix4().makeScale(x, y, z));
|
mesh.geometry.applyMatrix4(new THREE.Matrix4().makeScale(x, y, z));
|
||||||
|
if (this.outline) {
|
||||||
|
this.setEdges(true);
|
||||||
|
}
|
||||||
scale.x *= (x || 1.0);
|
scale.x *= (x || 1.0);
|
||||||
scale.y *= (y || 1.0);
|
scale.y *= (y || 1.0);
|
||||||
scale.z *= (z || 1.0);
|
scale.z *= (z || 1.0);
|
||||||
|
|
@ -558,6 +561,9 @@ class Widget {
|
||||||
if (center) {
|
if (center) {
|
||||||
this.center(false);
|
this.center(false);
|
||||||
}
|
}
|
||||||
|
if (this.outline) {
|
||||||
|
this.setEdges(true);
|
||||||
|
}
|
||||||
if ((x || y || z) && api && api.event) {
|
if ((x || y || z) && api && api.event) {
|
||||||
api.event.emit('widget.rotate', {widget: this, x, y, z});
|
api.event.emit('widget.rotate', {widget: this, x, y, z});
|
||||||
}
|
}
|
||||||
|
|
@ -698,7 +704,10 @@ class Widget {
|
||||||
|
|
||||||
getBoundingBox(refresh) {
|
getBoundingBox(refresh) {
|
||||||
if (!this.bounds || refresh || this.boundingBoxNeedsUpdate) {
|
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;
|
this.boundingBoxNeedsUpdate = false;
|
||||||
}
|
}
|
||||||
return this.bounds;
|
return this.bounds;
|
||||||
|
|
|
||||||
|
|
@ -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_dtru_l: ["additional drill depth below part bottom","overrides global z thru","0 to disable"],
|
||||||
cd_mark_s: "marking",
|
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_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_seli_l: ["individually select holes","to drill"],
|
||||||
cd_sela_s: "Select Matching Diameter",
|
cd_sela_s: "Select Matching Diameter",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue