add lathe leave stock option, fix lathe progression between layers

This commit is contained in:
Stewart Allen 2023-02-20 16:33:04 -05:00
commit 3e33e34598
6 changed files with 81 additions and 31 deletions

View file

@ -68,6 +68,7 @@
# CAM
* `B` roughing leave stock should also increase Z slightly (sqrt(2) * leave)
* `B` rapid moves should be max of terrain zmax and last cut layer height (roughing)
* `B` in indexed stock mode, stock should rotate with indexing
* `B` feed rate for next tool set before tool change (push/pop feed rates?)

View file

@ -1348,6 +1348,8 @@ CAM.init = function(kiri, api) {
angle: 'camLatheAngle',
rate: 'camLatheSpeed',
tolerance: 'camTolerance',
filter: 'camContourFilter',
leave: 'camContourLeave',
axis: 'X'
}).inputs = {
tool: UC.newSelect(LANG.cc_tool, {}, "tools"),
@ -1355,9 +1357,13 @@ CAM.init = function(kiri, api) {
sep: UC.newBlank({class:"pop-sep"}),
spindle: UC.newInput(LANG.cc_spnd_s, {title:LANG.cc_spnd_l, convert:UC.toInt, show:hasSpindle}),
rate: UC.newInput(LANG.cc_feed_s, {title:LANG.cc_feed_l, convert:UC.toInt, units:true}),
sep: UC.newBlank({class:"pop-sep"}),
step: UC.newInput(LANG.cc_sovr_s, {title:LANG.cc_sovr_l, convert:UC.toFloat, bound:UC.bound(0.01,10.0)}),
angle: UC.newInput(LANG.cc_sang_s, {title:LANG.cc_sang_l, convert:UC.toFloat, bound:UC.bound(0.01,90.0)}),
sep: UC.newBlank({class:"pop-sep"}),
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}),
leave: UC.newInput(LANG.cf_leav_s, {title:LANG.cf_leav_l, convert:UC.toFloat, bound:UC.bound(0,100)}),
// filter: UC.newRow([ UC.newButton(LANG.filter, contourFilter) ], {class:"ext-buttons f-row"})
};
createPopOp('trace', {

View file

@ -255,13 +255,14 @@ CAM.export = function(print, online) {
dx = opt.dx || newpos.x - pos.x,
dy = opt.dy || newpos.y - pos.y,
dz = opt.dz || newpos.z - pos.z,
da = newpos.a != pos.a,
maxf = dz ? maxZd : maxXYd,
feed = Math.min(speed || maxf, maxf),
dist = Math.sqrt(dx * dx + dy * dy + dz * dz),
newFeed = feed && feed !== pos.f;
// drop dup points (all deltas are 0)
if (!(dx || dy || dz)) {
if (!(dx || dy || dz || da)) {
return;
}
@ -285,7 +286,7 @@ CAM.export = function(print, online) {
runbox.max.z = Math.max(runbox.max.z, pos.z);
nl.append(space).append("Z").append(add0(pos.z * factor));
}
if (newpos.a !== pos.a) {
if (da) {
pos.a = newpos.a;
nl.append(space).append("A").append(add0(pos.a * factor));
}

View file

@ -749,6 +749,30 @@ class OpOutline extends CamOp {
}
}
function createFilter(op) {
let filter = slices => slices;
if (op.filter) {
try {
const obj = eval(`( ${op.filter.join('\n')} )`);
let idx = 0;
if (obj && obj.slices) {
const nadd = [];
filter = function(slices) {
for (let slice of slices) {
if (obj.slices(slice, idx++)) {
nadd.push(slice);
}
}
return nadd;
};
}
} catch (e) {
console.log('filter parse error', e, op.filter);
}
}
return filter;
}
class OpContour extends CamOp {
constructor(state, op) {
super(state, op);
@ -757,26 +781,7 @@ class OpContour extends CamOp {
async slice(progress) {
let { op, state } = this;
let { addSlices } = state;
let filter = slices => slices;
if (op.filter) {
try {
const obj = eval(`( ${op.filter.join('\n')} )`);
let idx = 0;
if (obj && obj.slices) {
const nadd = [];
filter = function(slices) {
for (let slice of slices) {
if (obj.slices(slice, idx++)) {
nadd.push(slice);
}
}
return nadd;
};
}
} catch (e) {
console.log('filter parse error', e, op.filter);
}
}
let filter = createFilter(op);
// we need topo for safe travel moves when roughing and outlining
// not generated when drilling-only. then all z moves use bounds max.
// also generates x and y contouring when selected
@ -869,6 +874,7 @@ class OpLathe extends CamOp {
async slice(progress) {
let { op, state } = this;
let { addSlices } = state;
let filter = createFilter(op);
this.topo = await CAM.Topo4({
op,
@ -877,6 +883,7 @@ class OpLathe extends CamOp {
progress(pct, msg);
},
ondone: (slices) => {
slices = filter(slices);
this.slices = slices;
addSlices(slices, false);
}
@ -893,6 +900,7 @@ class OpLathe extends CamOp {
let toolDiam = new CAM.Tool(settings, op.tool).fluteDiameter();
let stepover = toolDiam * op.step * 2;
let rez = topo.resolution;
setTool(op.tool, op.rate, op.plunge);
setSpindle(op.spindle);
@ -906,16 +914,42 @@ class OpLathe extends CamOp {
continue;
}
let last;
for (let path of slice.camLines) {
let latent;
path.forEachPoint((point, pidx) => {
camOut(point.clone(), pidx > 0, stepover);
if (last) {
const dz = Math.abs(last.z - point.z);
if (dz < rez) {
// latent point should still be included in
// preview b/c arcs would look like straight lines
latent = point.clone();
return;
}
if (latent) {
camOut(latent, true, stepover);
latent = undefined;
}
}
camOut(last = point.clone(), pidx > 0, stepover);
}, false);
if (latent) {
camOut(latent, true, stepover);
}
}
newLayer();
}
setPrintPoint(printPoint);
// move to safe height and reset A axis
let last = ops.lastPoint();
let amax = Math.round(last.a / 360) * 360;
camOut(last = last.clone().setZ(zmax), 0);
camOut(last = last.clone().setA(amax), 0);
newLayer();
ops.addGCode("G92A0");
setPrintPoint(last);
}
}

View file

@ -100,6 +100,7 @@ function prepEach(widget, settings, print, firstPoint, update) {
layerOut = [],
printPoint,
isNewMode,
isLathe,
tool,
toolType,
toolDiam,
@ -327,7 +328,7 @@ function prepEach(widget, settings, print, firstPoint, update) {
isMove = !cut;
// drop points too close together
if (deltaXY < 0.001 && point.z === lastPoint.z) {
if (!isLathe && deltaXY < 0.001 && point.z === lastPoint.z) {
// console.trace(["drop dup",lastPoint,point]);
return;
}
@ -346,7 +347,7 @@ function prepEach(widget, settings, print, firstPoint, update) {
// new pos for plunge calc
deltaXY = 0;
}
} else if (isMove && ['lathe'].contains(currentOp.type)) {
} else if (isMove && isLathe) {
if (point.z > lastPoint.z) {
layerPush(lastPoint.clone().setZ(point.z), 0, 0, tool.getNumber());
} else if (point.z < lastPoint.z) {
@ -392,7 +393,7 @@ function prepEach(widget, settings, print, firstPoint, update) {
}
// set new plunge rate
if (!lasering && deltaZ < -tolerance && currentOp.type !== 'lathe') {
if (!lasering && deltaZ < -tolerance && !isLathe) {
let threshold = Math.min(deltaXY / 2, absDeltaZ),
modifier = threshold / absDeltaZ;
if (synthPlunge && threshold && modifier && deltaXY > tolerance) {
@ -465,6 +466,7 @@ function prepEach(widget, settings, print, firstPoint, update) {
setTolerance(0);
nextIsMove = true;
currentOp = op.op;
isLathe = currentOp.type === 'lathe';
let weight = op.weight();
newLayer(op.op);
op.prepare(ops, (progress, message) => {

View file

@ -72,6 +72,7 @@ class Topo4 {
this.maxo = tool.profileDim.maxo * resolution;
this.diam = tool.fluteDiameter();
this.zoff = widget.track.top || 0;
this.leave = op.leave || 0;
onupdate(0, "lathe");
@ -90,6 +91,8 @@ class Topo4 {
onupdate(1, "lathe");
ondone(lathe);
// ondone([...slices, ...lathe]);
return this;
}
async slice(onupdate) {
@ -300,7 +303,7 @@ class Topo4 {
}
async latheWorker(onupdate) {
const { sliced, tool, zoff } = this;
const { sliced, tool, zoff, leave } = this;
const rota = this.angle * DEG2RAD;
const steps = (Math.PI * 2) / rota;
@ -335,7 +338,8 @@ class Topo4 {
for (let rec of recs) {
const { degrees, heights } = rec;
[...heights].group(3).forEach((a,i) => {
paths[i].camLines[0].push( newPoint(a[0], a[1], a[2]).setA(degrees) );
// progress each path 360 degrees to prevent A rolling backwards
paths[i].camLines[0].push( newPoint(a[0], a[1], a[2] + leave).setA(degrees+ i * -360) );
});
}
@ -345,7 +349,9 @@ class Topo4 {
console.log('empty', slice);
continue;
}
slice.camLines[0].push(poly.points[0].clone());
// repeat first point 360 degrees progressed
const repeat = poly.points[0];
slice.camLines[0].push(repeat.clone().setA(repeat.a - 360));
slice.output()
.setLayer("lathe", { line: 0xffff00 })
.addPoly(poly.clone().applyRotations().move({ z: -zoff, x:0, y:0 }));
@ -407,7 +413,7 @@ function rotatePoints(lines, rot) {
new THREE.BufferAttribute(lines, 3).applyMatrix4(rot);
}
CAM.Topo4 = async function(opt) {
CAM.Topo4 = function(opt) {
return new Topo4().generate(opt);
};