identify holes in arrange step
This commit is contained in:
parent
7bee55b9c7
commit
756e0dccb5
5 changed files with 151 additions and 46 deletions
|
|
@ -1162,8 +1162,18 @@ CAM.init = function(kiri, api) {
|
||||||
console.log("func.selectIndividualHoles not implemented");
|
console.log("func.selectIndividualHoles not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
func.selectAllHoles= function(){
|
func.selectAllHoles= function(data, getRec){
|
||||||
|
let settings = API.conf.get();
|
||||||
|
const {tool,mark} = getRec();
|
||||||
|
|
||||||
|
const diam = new CAM.Tool(settings,tool).fluteDiameter()
|
||||||
|
|
||||||
console.log("func.selectAllHoles not implemented");
|
console.log("func.selectAllHoles not implemented");
|
||||||
|
let holes = CAM.holes((centers)=>{ //cam holes takes <=0 diameter to mean select all holes
|
||||||
|
|
||||||
|
console.log("client received centers",centers)
|
||||||
|
|
||||||
|
},diam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1586,7 +1596,7 @@ CAM.init = function(kiri, api) {
|
||||||
menu: UC.newRow([ UC.newButton("select", func.surfaceAdd) ], {class:"ext-buttons f-row"}),
|
menu: UC.newRow([ UC.newButton("select", func.surfaceAdd) ], {class:"ext-buttons f-row"}),
|
||||||
};
|
};
|
||||||
|
|
||||||
createPopOp('drill', {
|
const drillOp =createPopOp('drill', {
|
||||||
tool: 'camDrillTool',
|
tool: 'camDrillTool',
|
||||||
spindle: 'camDrillSpindle',
|
spindle: 'camDrillSpindle',
|
||||||
down: 'camDrillDown',
|
down: 'camDrillDown',
|
||||||
|
|
@ -1595,7 +1605,9 @@ CAM.init = function(kiri, api) {
|
||||||
lift: 'camDrillLift',
|
lift: 'camDrillLift',
|
||||||
mark: 'camDrillMark',
|
mark: 'camDrillMark',
|
||||||
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}),
|
||||||
|
|
@ -1609,8 +1621,8 @@ CAM.init = function(kiri, api) {
|
||||||
sep: UC.newBlank({class:"pop-sep"}),
|
sep: UC.newBlank({class:"pop-sep"}),
|
||||||
actions: UC.newRow([
|
actions: UC.newRow([
|
||||||
UC.newButton(LANG.cd_select_s, func.selectIndividualHoles, {title:LANG.cd_select_l}),
|
UC.newButton(LANG.cd_select_s, func.selectIndividualHoles, {title:LANG.cd_select_l}),
|
||||||
UC.newButton(LANG.cd_selall_s, func.selectAllHoles, {title:LANG.cd_selall_l})
|
UC.newButton(LANG.cd_selall_s, (ev)=>func.selectAllHoles(ev, drillOp.createRecordGetter()), {title:LANG.cd_selall_l})
|
||||||
], {class:"ext-buttons f-row"})
|
], {class:"ext-buttons f-col"})
|
||||||
};
|
};
|
||||||
|
|
||||||
createPopOp('register', {
|
createPopOp('register', {
|
||||||
|
|
@ -1763,7 +1775,7 @@ function createPopOp(type, map) {
|
||||||
if( opType != "drill" && tool.type == "drill"){
|
if( opType != "drill" && tool.type == "drill"){
|
||||||
alerts.show(`Warning: Drills should not be used for ${opType} operations.`)
|
alerts.show(`Warning: Drills should not be used for ${opType} operations.`)
|
||||||
}
|
}
|
||||||
if( opType == "drill" && tool.type != "drill"){
|
else if( opType == "drill" && tool.type != "drill"){
|
||||||
alerts.show(`Warning: Only drills should be used for drilling operations.`)
|
alerts.show(`Warning: Only drills should be used for drilling operations.`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1825,6 +1837,20 @@ function createPopOp(type, map) {
|
||||||
group: [],
|
group: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function createRecordGetter
|
||||||
|
* @description Creates a getter function for the current record.
|
||||||
|
* The getter will bind the current record to the op before returning it.
|
||||||
|
* This is useful for passing a record to a pre-slice function
|
||||||
|
* @returns {function} A getter function for the current record.
|
||||||
|
*/
|
||||||
|
op.createRecordGetter = () => {
|
||||||
|
return () => {
|
||||||
|
op.bind();
|
||||||
|
return op.rec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UC.restore({
|
UC.restore({
|
||||||
addTo: op.div,
|
addTo: op.div,
|
||||||
bindTo: op.bind,
|
bindTo: op.bind,
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,21 @@ kiri.load(api => {
|
||||||
// console.log({clear_traces: true});
|
// console.log({clear_traces: true});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//0 or less diameter means select all holes
|
||||||
|
CAM.holes = function(ondone, diam) {
|
||||||
|
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)
|
||||||
|
|
||||||
|
console.log("output from driver",res)
|
||||||
|
|
||||||
|
ondone(res);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kiri.worker) {
|
if (kiri.worker) {
|
||||||
|
|
@ -143,6 +158,22 @@ kiri.load(api => {
|
||||||
}
|
}
|
||||||
send.done({});
|
send.done({});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
kiri.worker.cam_holes = async function(data, send) {
|
||||||
|
const { settings, diam } = data;
|
||||||
|
const widgets = Object.values(kiri.worker.cache);
|
||||||
|
const fresh = [];
|
||||||
|
for (let widget of widgets) {
|
||||||
|
if (await CAM.holes(settings, widget, diam)) {
|
||||||
|
fresh.push(widget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// const fresh = widgets.filter(widget => CAM.traces(settings, widget, single));
|
||||||
|
send.done(kiri.codec.encode(fresh.map(widget => { return {
|
||||||
|
id: widget.id,
|
||||||
|
holes: widget.holes,
|
||||||
|
} } )));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1476,43 +1476,7 @@ class OpDrill extends CamOp {
|
||||||
|
|
||||||
// for each slice, look for polygons with 98.5% circularity whose
|
// for each slice, look for polygons with 98.5% circularity whose
|
||||||
// area is within the tolerance of a circle matching the tool diameter
|
// area is within the tolerance of a circle matching the tool diameter
|
||||||
for (let slice of tslices) {
|
|
||||||
if (slice.z < zBottom) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let inner = slice.topPolyInners([]);
|
|
||||||
for (let poly of inner) {
|
|
||||||
if (poly.circularity() >= 0.985 && Math.abs(poly.area() - area) <= areaDelta) {
|
|
||||||
let center = poly.calcCircleCenter(),
|
|
||||||
merged = false,
|
|
||||||
closest = Infinity,
|
|
||||||
dist;
|
|
||||||
// TODO reject if inside camShellPolys (means there is material above)
|
|
||||||
if (center.isInPolygon(slice.shadow)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (let drill of drills) {
|
|
||||||
if (merged) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ((dist = drill.last().distTo2D(center)) <= centerDiff) {
|
|
||||||
merged = true;
|
|
||||||
drill.push(center);
|
|
||||||
}
|
|
||||||
closest = Math.min(closest,dist);
|
|
||||||
}
|
|
||||||
if (!merged) {
|
|
||||||
drills.push(newPolygon().append(center));
|
|
||||||
}
|
|
||||||
} else if (op.arcs) {
|
|
||||||
// find arcs
|
|
||||||
let arcs = poly.findArcCenters();
|
|
||||||
for (let arc of arcs) {
|
|
||||||
drills.push(newPolygon().add(arc.x,arc.y,arc.z||0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// drill points to use center (average of all points) of the polygon
|
// drill points to use center (average of all points) of the polygon
|
||||||
drills.forEach(function(drill) {
|
drills.forEach(function(drill) {
|
||||||
|
|
|
||||||
|
|
@ -332,9 +332,11 @@ CAM.slice = async function(settings, widget, onupdate, ondone) {
|
||||||
widget.minToolDiam = minToolDiam;
|
widget.minToolDiam = minToolDiam;
|
||||||
widget.maxToolDiam = maxToolDiam;
|
widget.maxToolDiam = maxToolDiam;
|
||||||
|
|
||||||
ondone();
|
ondone(state);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CAM.addDogbones = function(poly, dist, reverse) {
|
CAM.addDogbones = function(poly, dist, reverse) {
|
||||||
if (Array.isArray(poly)) {
|
if (Array.isArray(poly)) {
|
||||||
return poly.forEach(p => CAM.addDogbones(p, dist));
|
return poly.forEach(p => CAM.addDogbones(p, dist));
|
||||||
|
|
@ -421,6 +423,8 @@ CAM.traces = async function(settings, widget, single) {
|
||||||
traces.push(poly);
|
traces.push(poly);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let opts = { each: oneach, over: false, flatoff: 0, edges: true, openok: true, lines: true };
|
let opts = { each: oneach, over: false, flatoff: 0, edges: true, openok: true, lines: true };
|
||||||
await slicer.slice(indices, opts);
|
await slicer.slice(indices, opts);
|
||||||
// pick up bottom features
|
// pick up bottom features
|
||||||
|
|
@ -431,6 +435,86 @@ CAM.traces = async function(settings, widget, single) {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
CAM.holes = async function(settings, widget, diam) {
|
||||||
|
|
||||||
|
let proc = settings.process,
|
||||||
|
stock = settings.stock || {},
|
||||||
|
isIndexed = proc.camStockIndexed,
|
||||||
|
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;
|
||||||
|
|
||||||
|
let slicer = new kiri.cam_slicer(widget);
|
||||||
|
|
||||||
|
let zees = Object.assign({}, slicer.zFlat);
|
||||||
|
let indices = [...new Set(Object.keys(zees)
|
||||||
|
.map(kv => parseFloat(kv).round(5))
|
||||||
|
.filter(z => z !== null)
|
||||||
|
)]
|
||||||
|
|
||||||
|
|
||||||
|
let centerDiff = diam * 0.1,
|
||||||
|
area = (diam/2) * (diam/2) * Math.PI,
|
||||||
|
areaDelta = area * 0.05,
|
||||||
|
drills = [];
|
||||||
|
|
||||||
|
let slices = [];
|
||||||
|
|
||||||
|
function onEach(slice) {
|
||||||
|
slices.push(slice);
|
||||||
|
}
|
||||||
|
|
||||||
|
let opts = { each: onEach, over: false, flatoff: 0, edges: true, openok: false, lines: false };
|
||||||
|
await slicer.slice(indices, opts);
|
||||||
|
|
||||||
|
const tslices = slices.map(s=>s.tops).flat()
|
||||||
|
|
||||||
|
for (let slice of tslices) {
|
||||||
|
|
||||||
|
slice.shadow = CAM.shadowAt(widget,slice.z, 0)
|
||||||
|
console.log("looking at slice",slice)
|
||||||
|
|
||||||
|
let inner = slice.inner;
|
||||||
|
for (let poly of inner) {
|
||||||
|
if (poly.circularity() >= 0.985 && Math.abs(poly.area() - area) <= areaDelta) {
|
||||||
|
let center = poly.calcCircleCenter();
|
||||||
|
|
||||||
|
if (center.isInPolygon(slice.shadow)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let overlap = false;
|
||||||
|
for (let [i,drill] of drills.entries()) {
|
||||||
|
let dist = drill.distTo2D(center)
|
||||||
|
if (dist <= centerDiff) { // too close
|
||||||
|
|
||||||
|
console.log("overlap",center,drill);
|
||||||
|
if(center.z > drill.z) { //if current is higher than old
|
||||||
|
|
||||||
|
drills[i] = center;
|
||||||
|
}
|
||||||
|
// otherwise, don't add and continue
|
||||||
|
overlap = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!overlap) drills.push(center);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("drills returned",drills)
|
||||||
|
widget.holes = drills;
|
||||||
|
return drills;
|
||||||
|
}
|
||||||
|
|
||||||
function cutTabs(tabs, offset, z, inter) {
|
function cutTabs(tabs, offset, z, inter) {
|
||||||
tabs = tabs.filter(tab => z < tab.pos.z + tab.dim.z/2).map(tab => tab.off).flat();
|
tabs = tabs.filter(tab => z < tab.pos.z + tab.dim.z/2).map(tab => tab.off).flat();
|
||||||
return cutPolys(tabs, offset, z, false);
|
return cutPolys(tabs, offset, z, false);
|
||||||
|
|
|
||||||
|
|
@ -600,9 +600,9 @@ self.kiri.lang['en-us'] = {
|
||||||
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_select_s: "select individual",
|
cd_select_s: "Select Individual",
|
||||||
cd_select_l: ["individually select holes","to drill"],
|
cd_select_l: ["individually select holes","to drill"],
|
||||||
cd_selall_s: "select all",
|
cd_selall_s: "Select Matching Diameter",
|
||||||
cd_selall_l: ["select all holes that", "match selected tool diameter"],
|
cd_selall_l: ["select all holes that", "match selected tool diameter"],
|
||||||
|
|
||||||
// CNC FLIP
|
// CNC FLIP
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue