grid-apps-cmms/src/kiri/mode/cam/op-level.js
Stewart Allen e0b1c4e31f CAM routing refactor, area operation, and taper ball tool implementation
Major routing improvements:
- Refactor depth-first routing algorithm for better path optimization
- Reimplemented outline, roughing, pocket, and trace as area operation wrappers
- Add pocket shadow travel routing with optimized descent using travel bounds
- Improve contour routing with arc detection and polyEmit arc strategy
- Add area smoothing and ease-down options
- Fix outline handling with thru holes and surface reversal on tip2tip
- Move widget shadow methods into widget class for faster hole detection
- Better camInnerFirst support and proper feed/plunge defaults

Tool system improvements:
- Implement taper ball tool type with full support
- Add renderTool2() for profile-based visualization
- Convert tool menu to init code with bound vars
- Fix auto tool and auto spindle for prep operations
- Update tool profile generation for taperball geometry
- Add calcTaperBallExtent() for proper ball tangency calculations

Code cleanup:
- Remove duplicated slicer code from specialized slicers
- Asyncify shadowAt operations
- Deprecate pocket engrave operation
- Simplify upNover implementation
- Fix animation with new tool+settings requirements
2025-12-06 00:09:17 -05:00

73 lines
2.5 KiB
JavaScript

/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
import { CamOp } from './op.js';
import { Tool } from './tool.js';
import { newPolygon } from '../../../geo/polygon.js';
import { polygons as POLY } from '../../../geo/polygons.js';
import { newSlice } from '../../core/slice.js';
import { util } from '../../../geo/base.js';
class OpLevel extends CamOp {
constructor(state, op) {
super(state, op);
}
async slice(progress) {
let { op, state } = this;
let { addSlices, color, settings, shadow, updateToolDiams, zMax, ztOff } = state;
let { down, tool, step, stepz, inset } = op;
let { stock } = settings;
let toolDiam = new Tool(settings, tool).fluteDiameter();
let stepOver = this.stepOver = toolDiam * step;
let wpos = state.widget.track.pos;
let zTop = zMax + ztOff;
let zBot = zTop - down;
let zList = stepz && down ? util.lerp(zTop, zBot, stepz) : [ zBot ];
updateToolDiams(toolDiam);
let points = [];
let clear = op.stock ?
[ newPolygon().centerRectangle({x:-wpos.x,y:-wpos.y,z:wpos.z}, stock.x + toolDiam/2, stock.y) ] :
POLY.outer(POLY.offset(shadow.base, toolDiam * (inset || 0)));
POLY.fillArea(clear, 1090, stepOver, points);
let layers = this.layers = [];
for (let z of zList) {
let lines = [];
layers.push(lines);
for (let i=0; i<points.length; i += 2) {
let slice = newSlice(z);
lines.push( newPolygon().setOpen().addPoints([ points[i], points[i+1] ]).setZ(z) );
slice.output()
.setLayer("level", {face: color, line: color})
.addPolys(lines);
addSlices(slice);
}
}
}
prepare(ops, progress) {
let { layers, stepOver } = this;
let { printPoint } = ops;
let { newLayer, tip2tipEmit, camOut } = ops;
for (let lines of layers) {
lines = lines.map(p => { return { first: p.first(), last: p.last(), poly: p } });
printPoint = tip2tipEmit(lines, printPoint, (el, point, count) => {
let poly = el.poly;
if (poly.last() === point) {
poly.reverse();
}
poly.forEachPoint((point, pidx) => {
camOut(point.clone(), true, stepOver);
}, false);
});
newLayer();
}
}
}
export { OpLevel };