2025-07-05 10:49:09 -04:00
|
|
|
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
|
|
|
|
|
2026-01-08 16:52:41 -05:00
|
|
|
import { CamOp } from '../core/op.js';
|
|
|
|
|
import { Tool } from '../core/tool.js';
|
2025-07-05 15:21:26 -04:00
|
|
|
import { generate as Topo } from './topo3.js';
|
2026-01-08 16:52:41 -05:00
|
|
|
import { newPoint } from '../../../../geo/point.js';
|
|
|
|
|
import { newPolygon } from '../../../../geo/polygon.js';
|
|
|
|
|
import { newSlice } from '../../../core/slice.js';
|
|
|
|
|
import { tip2tipEmit } from '../../../../geo/paths.js';
|
2025-07-05 10:49:09 -04:00
|
|
|
|
2025-10-12 16:01:38 -04:00
|
|
|
function createFilter(op, origin, axis) {
|
2025-10-31 22:53:37 -04:00
|
|
|
// console.log({ origin, axis });
|
2025-10-12 16:01:38 -04:00
|
|
|
let ok = () => true;
|
2025-07-05 10:49:09 -04:00
|
|
|
let filter = slices => slices;
|
2025-07-05 23:07:36 -04:00
|
|
|
let filterString = op.filter?.map(l => l.trim()).join('\n');
|
|
|
|
|
if (filterString) {
|
2025-07-05 10:49:09 -04:00
|
|
|
try {
|
2025-07-05 23:07:36 -04:00
|
|
|
const obj = eval(`( ${filterString} )`);
|
2025-10-12 16:01:38 -04:00
|
|
|
let box = obj?.box;
|
|
|
|
|
let slice_fn = obj?.slices;
|
|
|
|
|
let index = 0;
|
|
|
|
|
const accept = [];
|
|
|
|
|
filter = function (slices) {
|
2026-03-09 21:40:03 -04:00
|
|
|
for (let slice of slices.filter(s => s.camLines)) {
|
2025-10-12 16:01:38 -04:00
|
|
|
if (slice_fn && slice_fn(slice, index++)) {
|
|
|
|
|
accept.push(slice);
|
|
|
|
|
} else if (box) {
|
|
|
|
|
// slice.z = x when axis = y
|
|
|
|
|
// slice.z = y when axis = x
|
|
|
|
|
let { x, y, z } = box;
|
|
|
|
|
x = x ?? [ -Infinity, Infinity ];
|
|
|
|
|
y = y ?? [ -Infinity, Infinity ];
|
|
|
|
|
z = z ?? [ -Infinity, Infinity ];
|
|
|
|
|
let ok = false;
|
|
|
|
|
if (axis === 'x') {
|
|
|
|
|
let sy = slice.z + origin.y;
|
|
|
|
|
if (sy >= y[0] && sy <= y[1]) {
|
|
|
|
|
ok = true;
|
|
|
|
|
for (let p of slice.camLines) {
|
|
|
|
|
p.points = p.points.filter(p =>
|
|
|
|
|
p.x - origin.x >= x[0] && p.x - origin.x <= x[1] &&
|
|
|
|
|
p.z - origin.z >= z[0] && p.z - origin.z <= z[1]
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
let sx = slice.z - origin.x;
|
|
|
|
|
if (sx >= x[0] && sx <= x[1]) {
|
|
|
|
|
ok = true;
|
|
|
|
|
for (let p of slice.camLines) {
|
|
|
|
|
p.points = p.points.filter(p =>
|
|
|
|
|
p.y + origin.y >= y[0] && p.y + origin.y <= y[1] &&
|
|
|
|
|
p.z - origin.z >= z[0] && p.z - origin.z <= z[1]
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ok) {
|
|
|
|
|
slice.camLines = slice.camLines.map(p => {
|
|
|
|
|
if (p.points.length > 1) {
|
|
|
|
|
return newPolygon(p.points).setOpen(true);
|
|
|
|
|
} else {
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
}).filter(p => p);
|
|
|
|
|
accept.push(slice);
|
2025-07-05 10:49:09 -04:00
|
|
|
}
|
|
|
|
|
}
|
2025-10-12 16:01:38 -04:00
|
|
|
}
|
|
|
|
|
return accept;
|
|
|
|
|
};
|
2025-07-05 10:49:09 -04:00
|
|
|
} catch (e) {
|
|
|
|
|
console.log('filter parse error', e, op.filter);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return filter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class OpContour extends CamOp {
|
|
|
|
|
constructor(state, op) {
|
|
|
|
|
super(state, op);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async slice(progress) {
|
|
|
|
|
let { op, state } = this;
|
2025-10-12 16:01:38 -04:00
|
|
|
let { color, addSlices, settings, updateToolDiams } = state;
|
2026-01-01 10:14:10 -05:00
|
|
|
|
2025-12-06 00:09:17 -05:00
|
|
|
let conTool = new Tool(settings, op.tool);
|
2025-10-12 16:01:38 -04:00
|
|
|
let filter = createFilter(op, settings.origin, op.axis.toLowerCase());
|
2025-12-06 00:09:17 -05:00
|
|
|
let toolDiam = this.toolDiam = conTool.fluteDiameter();
|
|
|
|
|
this.toolStep = conTool.getStepSize(op.step);
|
2025-11-30 18:03:18 -05:00
|
|
|
|
2025-07-16 01:44:22 -04:00
|
|
|
updateToolDiams(toolDiam);
|
2025-12-06 00:09:17 -05:00
|
|
|
|
2025-07-05 10:49:09 -04:00
|
|
|
// 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
|
2025-12-31 22:59:09 -05:00
|
|
|
let topo = this.topo = await Topo({
|
2025-07-05 10:49:09 -04:00
|
|
|
// onupdate: (update, msg) => {
|
|
|
|
|
onupdate: (index, total, msg) => {
|
|
|
|
|
progress(index / total, msg);
|
|
|
|
|
},
|
|
|
|
|
ondone: (slices) => {
|
|
|
|
|
slices = filter(slices);
|
|
|
|
|
this.sliceOut = slices;
|
|
|
|
|
addSlices(slices);
|
2025-10-12 16:01:38 -04:00
|
|
|
for (let slice of slices) {
|
|
|
|
|
slice.output()
|
|
|
|
|
.setLayer(`contour ${op.axis}`, { face: color, line: color })
|
|
|
|
|
.addPolys(slice.camLines);
|
|
|
|
|
}
|
2025-07-05 10:49:09 -04:00
|
|
|
},
|
|
|
|
|
contour: op,
|
2025-12-14 15:41:45 -05:00
|
|
|
state
|
2025-07-05 10:49:09 -04:00
|
|
|
});
|
2025-11-30 18:03:18 -05:00
|
|
|
|
2026-01-01 00:22:37 -05:00
|
|
|
if (this.debug && topo.coastline) {
|
|
|
|
|
console.log('coastline', topo.coastline);
|
|
|
|
|
const dbs = newSlice(-1);
|
|
|
|
|
const dbo = dbs.output();
|
|
|
|
|
dbo.setLayer("coastline", { line: 0x0000dd }).addPolys(topo.coastline);
|
|
|
|
|
addSlices([ dbs ])
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-05 10:49:09 -04:00
|
|
|
// computed if set to 0
|
|
|
|
|
this.tolerance = topo.tolerance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
prepare(ops, progress) {
|
2025-12-31 22:59:09 -05:00
|
|
|
let { op, sliceOut, state, toolStep, topo } = this;
|
2025-11-11 15:06:05 -05:00
|
|
|
let { settings } = state;
|
2025-07-05 10:49:09 -04:00
|
|
|
let { process } = settings;
|
|
|
|
|
|
2025-12-06 00:09:17 -05:00
|
|
|
let { polyEmit, setContouring, setTolerance, setTool } = ops;
|
2025-12-27 10:28:07 -05:00
|
|
|
let { widget, newLayer, zmax } = ops;
|
2025-07-05 10:49:09 -04:00
|
|
|
|
2025-11-30 18:03:18 -05:00
|
|
|
let bounds = widget.getBoundingBox();
|
2025-07-05 10:49:09 -04:00
|
|
|
let depthData = [];
|
|
|
|
|
|
|
|
|
|
setTool(op.tool, op.rate, process.camFastFeedZ);
|
2025-12-31 22:59:09 -05:00
|
|
|
setContouring(true, toolStep * 1.5, topo.coastline);
|
2025-07-05 10:49:09 -04:00
|
|
|
setTolerance(this.tolerance);
|
|
|
|
|
|
2025-11-30 18:03:18 -05:00
|
|
|
let printPoint = newPoint(bounds.min.x, bounds.min.y, zmax);
|
2025-07-05 10:49:09 -04:00
|
|
|
|
|
|
|
|
for (let slice of sliceOut) {
|
|
|
|
|
// ignore debug slices
|
|
|
|
|
if (!slice.camLines) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2025-11-11 15:06:05 -05:00
|
|
|
let polys = [], poly;
|
2025-12-06 00:09:17 -05:00
|
|
|
slice.camLines.forEach((poly) => {
|
|
|
|
|
poly = poly.clone(true).annotate({ slice: slice.index + 1 });
|
2025-07-15 18:36:35 -04:00
|
|
|
polys.push({ first: poly.first(), last: poly.last(), poly: poly });
|
2025-07-05 10:49:09 -04:00
|
|
|
});
|
2025-12-06 00:09:17 -05:00
|
|
|
depthData.appendAll(polys);
|
2025-07-05 10:49:09 -04:00
|
|
|
}
|
|
|
|
|
|
2025-12-06 00:09:17 -05:00
|
|
|
tip2tipEmit(depthData, printPoint, (el, point) => {
|
|
|
|
|
let poly = el.poly;
|
|
|
|
|
if (poly.last() === point) {
|
|
|
|
|
poly.reverse();
|
|
|
|
|
}
|
|
|
|
|
polyEmit(poly);
|
|
|
|
|
newLayer();
|
|
|
|
|
});
|
2025-07-05 10:49:09 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export { OpContour };
|