experimental async threaded cam topo

This commit is contained in:
Stewart Allen 2023-01-08 14:04:02 -05:00
commit db13a61d3b
9 changed files with 158 additions and 35 deletions

View file

@ -33,7 +33,7 @@ class CamOp {
return 1;
}
slice() { }
async slice() { }
prepare() { }
}
@ -106,7 +106,7 @@ class OpLevel extends CamOp {
super(state, op);
}
slice(progress) {
async slice(progress) {
let { op, state } = this;
let { settings, widget, addSlices } = state;
let { updateToolDiams, tabs, cutTabs } = state;
@ -164,7 +164,7 @@ class OpRough extends CamOp {
super(state, op);
}
slice(progress) {
async slice(progress) {
let { op, state } = this;
let { settings, widget, slicer, addSlices, unsafe, color } = state;
let { updateToolDiams, thruHoles, tabs, cutTabs, cutPolys } = state;
@ -476,7 +476,7 @@ class OpOutline extends CamOp {
super(state, op);
}
slice(progress) {
async slice(progress) {
let { op, state } = this;
let { settings, widget, slicer, addSlices, tshadow, thruHoles, unsafe, color } = state;
let { updateToolDiams, zThru, zBottom, shadowTop, tabs, cutTabs, cutPolys } = state;
@ -727,13 +727,13 @@ class OpContour extends CamOp {
super(state, op);
}
slice(progress) {
async slice(progress) {
let { op, state } = this;
let { addSlices } = state;
// 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
let topo = new CAM.Topo({
let topo = await CAM.Topo({
// onupdate: (update, msg) => {
onupdate: (index, total, msg) => {
progress(index / total, msg);
@ -816,7 +816,7 @@ class OpTrace extends CamOp {
super(state, op);
}
slice(progress) {
async slice(progress) {
let { op, state } = this;
let { tool, rate, down, plunge, offset, thru } = op;
let { settings, widget, addSlices, zMax, zTop, zThru, tabs } = state;
@ -1019,7 +1019,7 @@ class OpPocket extends CamOp {
super(state, op);
}
slice(progress) {
async slice(progress) {
const pocket = this;
const debug = false;
let { op, state } = this;
@ -1036,7 +1036,7 @@ class OpPocket extends CamOp {
let engrave = contour && op.engrave;
if (contour) {
down = 0;
this.topo = new CAM.Topo({
this.topo = await CAM.Topo({
// onupdate: (update, msg) => {
onupdate: (index, total, msg) => {
progress((index / total) * 0.9, msg);
@ -1242,7 +1242,7 @@ class OpDrill extends CamOp {
super(state, op);
}
slice(progress) {
async slice(progress) {
let { op, state } = this;
let { settings, addSlices, tslices, updateToolDiams } = state;
let { zBottom, zThru, thruHoles, color } = state;
@ -1332,7 +1332,7 @@ class OpRegister extends CamOp {
super(state, op);
}
slice(progress) {
async slice(progress) {
let { op, state } = this;
let { settings, widget, bounds, addSlices, zMax, zThru, color } = state;
let { updateToolDiams } = state;
@ -1484,7 +1484,7 @@ class OpXRay extends CamOp {
super(state, op);
}
slice(progress) {
async slice(progress) {
let { widget, addSlices } = this.state;
let slicer = new kiri.cam_slicer(widget.getPoints(), {
zlist: true,
@ -1512,26 +1512,21 @@ class OpShadow extends CamOp {
super(state, op);
}
slice(progress) {
async slice(progress) {
let state = this.state;
let { ops, slicer, widget, unsafe, addSlices, shadowAt } = state;
let real = ops.map(rec => rec.op).filter(op => op);
let drill = real.filter(op => op.type === 'drill').length > 0;
let rough = real.filter(op => op.type === 'rough').length > 0;
let outline = real.filter(op => op.type === 'outline').length > 0;
let outlineOut = real.filter(op => op.type === 'outline' && op.outside).length > 0;
let realOps = ops.map(rec => rec.op).filter(op => op);
let trueShadow = state.settings.process.camTrueShadow === true;
let minStepDown = real
let minStepDown = realOps
.map(op => (op.down || 3) / (trueShadow ? 1 : 3))
.reduce((a,v) => Math.min(a, v, 1));
let tslices = [];
let tshadow = [];
let tzindex = slicer.interval(minStepDown, { fit: true, off: 0.01, down: true, flats: true });
let complex = tzindex.length > 50 || widget.vertices.length > 1000000;
let skipTerrain = unsafe;// || (!rough && !outline && !drill && complex);
let skipTerrain = unsafe;
if (skipTerrain) {
console.log("skipping terrain generation");
@ -1540,7 +1535,6 @@ class OpShadow extends CamOp {
let lsz; // only shadow up to bottom of last shadow for progressive union
let terrain = slicer.slice(tzindex, { each: (data, index, total) => {
// let shadow = trueShadow ? CAM.shadowAt(widget, data.z, lsz) : [];
let shadow = trueShadow ? shadowAt(data.z, lsz) : [];
tshadow = POLY.union(tshadow.slice().appendAll(data.tops).appendAll(shadow), 0.01, true);
tslices.push(data.slice);

View file

@ -26,7 +26,7 @@ const POLY = polygons;
* @param {Widget} widget
* @param {Function} output
*/
CAM.slice = function(settings, widget, onupdate, ondone) {
CAM.slice = async function(settings, widget, onupdate, ondone) {
let mesh = widget.mesh,
proc = settings.process,
stock = settings.stock || {},
@ -238,7 +238,7 @@ CAM.slice = function(settings, widget, onupdate, ondone) {
setAxisIndex();
for (let op of opList) {
let weight = op.weight();
op.slice((progress, message) => {
await op.slice((progress, message) => {
onupdate((opSum + (progress * weight)) / opTot, message || op.type());
});
tracker.rotation = isIndexed ? axisRotation : 0;

View file

@ -5,6 +5,7 @@
/**
* Slicing engine used by CAM
*/
// dep: kiri.slice
gapp.register("kiri-mode.cam.slicer", [], (root, exports) => {
const { base, kiri } = root;
@ -14,13 +15,18 @@ const { newSlice } = kiri;
const POLY = polygons;
class Slicer {
constructor(points, options) {
constructor(points, options = {}) {
this.options = {};
this.setOptions(options);
if (points) {
this.setPoints(points, options);
}
}
get threaded() {
return this.options.threaded;
}
// notopok = when genso set, allow empty top array
// emptyok = allow empty slices
// openok = allow open tops
@ -129,10 +135,12 @@ class Slicer {
let zSum = this.zSum;
let zMax = this.bounds.max.z;
let points = this.points;
let bucketCount = Math.max(1, Math.ceil(zMax / (zSum / points.length)) - 1);
let bucketCount = this.threaded ? 0 : Math.max(1, Math.ceil(zMax / (zSum / points.length)) - 1);
let zScale = this.zScale = 1 / (zMax / bucketCount);
let buckets = this.buckets = {};
if (bucketCount > 1) {
buckets.length = bucketCount;
// create empty buckets
let min = Math.floor(bounds.min.z * zScale);
let max = Math.ceil(bounds.max.z * zScale);
@ -158,6 +166,14 @@ class Slicer {
return this;
}
async sliceAsync(zarr, options) {
if (!this.threaded) {
return this.slice(zarr, options);
}
return await kiri.minions.camSliceZ(zarr, this, options);
// return this.slice(zarr, options);
}
// slice through points at given Z and return polygons
slice(z, options, index, total, mark) {
const opt = this.setOptions(options);

View file

@ -21,11 +21,14 @@ const POLY = polygons;
const RAD2DEG = 180 / Math.PI;
class Topo {
constructor(opt = {}) {
constructor() { }
async generate(opt = {}) {
let { state, contour, onupdate, ondone } = opt;
let { widget, settings, tshadow, center, tabs, color } = opt.state;
let density = parseInt(settings.controller.animesh || 100) * 2500,
let { controller, process } = settings,
density = parseInt(controller.animesh || 100) * 2500,
axis = contour.axis.toLowerCase(),
contourX = axis === "x",
contourY = axis === "y",
@ -33,7 +36,6 @@ class Topo {
tolerance = contour.tolerance,
flatness = contour.flatness || 0.005,
bridge = contour.bridging || 0,
proc = settings.process,
shadow = tshadow,
minX = bounds.min.x,
maxX = bounds.max.x,
@ -73,7 +75,7 @@ class Topo {
newslices = [],
tabsMax = tabs ? Math.max(...tabs.map(tab => tab.dim.z/2 + tab.pos.z)) : 0,
tabsOn = tabs,
tabHeight = Math.max(proc.camTabsHeight + zBottom, tabsMax),
tabHeight = Math.max(process.camTabsHeight + zBottom, tabsMax),
clipTab = tabsOn ? [] : null,
clipTo = inside ? shadow : POLY.expand(shadow, toolDiameter/2 + resolution * 3),
partOff = inside ? 0 : toolDiameter / 2 + resolution,
@ -437,21 +439,25 @@ class Topo {
let points = base.verticesToPoints(widget.getGeoVertices(true, true));
let slicer = new kiri.cam_slicer(points, {
swapX: true, emptyok: true, notopok: true
swapX: true, emptyok: true, notopok: true, threaded: controller.threaded
});
let sindex = slicer.interval(resolution);
if (!topo.slices) stepsTotal += sindex.length * 2;
if (contourX) stepsTotal += Math.round((maxY-minY) / toolStep);
if (contourY) stepsTotal += Math.round((maxX-minX) / toolStep);
let slices = topo.slices = topo.slices || slicer.slice(sindex, { each: (data, index, total) => {
let slices = topo.slices = topo.slices || await slicer.sliceAsync(sindex, { each: (data, index, total) => {
onupdate(++stepsTaken, stepsTotal, "topo slice");
}, genso: true });
processSlices(slices.filter(s => s.lines).map(data => data.slice));
return this;
}
}
CAM.Topo = Topo;
CAM.Topo = async function(opt) {
return new Topo().generate(opt);
};
});

View file

@ -35,6 +35,7 @@ FDM.init = function(kiri, api) {
const { ui, uc } = api;
const rangeVars = {
// slice
// "sliceHeight": LANG.sl_lahi_s,
"sliceShells": LANG.sl_shel_s,
"sliceFillType": LANG.fi_type,
"sliceFillWidth": LANG.fi_wdth_s,

View file

@ -296,7 +296,7 @@ FDM.slice = function(settings, widget, onupdate, ondone) {
z += h;
}
}
// reduce slice position by half height
// reduce slice position by half layer height
for (let i=0; i<zi.length; i++) {
zi[i] = (zi[i] - zh[i] / 2).round(3);
}