add global slicePre similar to sliceAll (which should be renamed slicePost)

add shared cam operational state so index+stock can run once for all instances
This commit is contained in:
Stewart Allen 2026-01-03 11:42:37 -05:00
commit 87e4a32092
6 changed files with 70 additions and 13 deletions

View file

@ -137,6 +137,10 @@ function prepareSlices(callback, scale = 1, offset = 0) {
client.rotate(settings);
}
function sliceSetup() {
client.slicePre(settings, sliceNext);
}
function sliceNext() {
if (toSlice.length) {
// while more widgets to slice
@ -309,8 +313,9 @@ function prepareSlices(callback, scale = 1, offset = 0) {
space.refresh();
}
// kick off slicing chain
sliceNext();
// do any global setup / state management
// then kick off slicing chain
sliceSetup();
}
/**

View file

@ -211,6 +211,13 @@ export const client = {
});
},
// called once at the beginning of slice operations
// setup any global shared state
slicePre(settings, callback) {
send("slicePre", { settings }, callback);
},
// called once for each widget
slice(settings, widget, callback) {
send("slice", {

View file

@ -1,7 +1,7 @@
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
import { codec } from '../../core/codec.js';
import { cam_slice, holes, traces } from './slice.js';
import { cam_slice_pre, cam_slice, holes, traces } from './slice.js';
import { cam_prepare } from './prepare.js';
import { cam_export } from './export.js';
import { tool as mesh_tool } from '../../../mesh/tool.js';
@ -114,6 +114,7 @@ export const CAM = {
init,
surface_prep,
surface_find,
slicePre: cam_slice_pre,
slice: cam_slice,
prepare: cam_prepare,
export: cam_export

View file

@ -14,9 +14,11 @@ class OpLevel extends CamOp {
async slice(progress) {
let { op, state } = this;
let { addSlices, color, settings, shadow, updateToolDiams, zMax, ztOff } = state;
let { addSlices, color, settings, shadow } = state;
let { share, updateToolDiams, zMax, ztOff } = state;
let { down, tool, step, stepz, inset } = op;
let { stock } = settings;
let { center } = stock;
let toolDiam = new Tool(settings, tool).fluteDiameter();
let stepOver = this.stepOver = toolDiam * step;
@ -25,11 +27,23 @@ class OpLevel extends CamOp {
let zBot = zTop - down;
let zList = stepz && down ? util.lerp(zTop, zBot, stepz) : [ zBot ];
if (share.ran) {
console.log('skip');
this.skip = true;
return;
} else if (op.stock) {
share.ran = true;
}
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) ] :
[ newPolygon().centerRectangle({
x: -wpos.x + center.x,
y: -wpos.y + center.y,
z: wpos.z + center.z
}, stock.x + toolDiam/2, stock.y) ] :
POLY.outer(POLY.offset(shadow.base, toolDiam * (inset || 0)));
POLY.fillArea(clear, 1090, stepOver, points);
@ -50,10 +64,14 @@ class OpLevel extends CamOp {
}
prepare(ops, progress) {
let { layers, stepOver } = this;
let { layers, skip, stepOver } = this;
let { printPoint } = ops;
let { newLayer, tip2tipEmit, camOut } = ops;
if (skip) {
return;
}
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) => {

View file

@ -11,6 +11,13 @@ import { Slicer as cam_slicer } from './slicer_cam.js';
import { Tool } from './tool.js';
import { util } from '../../../geo/base.js';
// state shared across all widget slicing
let shared;
export function cam_slice_pre(settings) {
shared = { ops: { } };
}
/**
* DRIVER SLICE CONTRACT
*
@ -306,7 +313,7 @@ export async function cam_slice(settings, widget, onupdate, ondone) {
}
if (false) {
opList.push(new OPS.xray(state, { type: "xray" }));
opList.push({ op: new OPS.xray(state, { type: "xray" }) });
}
// find index ops
@ -315,14 +322,14 @@ export async function cam_slice(settings, widget, onupdate, ondone) {
if (isIndexed) {
// preface op list with OpIndex
if (activeOps.length === 0 || activeOps[0].type !== 'index') {
opList.push(new OPS.index(state, { type: "index", degrees: 0, absolute: true }));
opTot += opList.peek().weight();
opList.push({ op: new OPS.index(state, { type: "index", degrees: 0, absolute: true }) });
opTot += opList.peek().op.weight();
}
} else {
// preface op list with OpShadow
opList.push(new OPS.shadow(state, { type: "shadow", silent: true }));
opTot += opList.peek().weight();
opList.push({ op: new OPS.shadow(state, { type: "shadow", silent: true }) });
opTot += opList.peek().op.weight();
}
// LOOP EXPANSION - duplicate next N operations M times
@ -354,6 +361,7 @@ export async function cam_slice(settings, widget, onupdate, ondone) {
activeOps = expandedOps;
// determine # of steps and step weighting for progress bar
let opos = 0;
for (let op of activeOps) {
if (op.type === '|') {
break;
@ -361,15 +369,20 @@ export async function cam_slice(settings, widget, onupdate, ondone) {
let opfn = OPS[op.type];
if (opfn) {
let opin = new opfn(state, op);
opList.push(opin);
opTot += opin.weight();
opos++;
let share = shared.ops[opos];
if (!share) {
share = shared.ops[opos] = {};
}
opList.push({ op: opin, share });
}
}
// call slice() function on all ops in order
await setAxisIndex();
updateSlicer();
for (let op of opList) {
for (let { op, share } of opList) {
let weight = op.weight();
// apply operation override vars
let workover = var_compute();
@ -392,6 +405,7 @@ export async function cam_slice(settings, widget, onupdate, ondone) {
let layername = named.length ? named : (note ? `${type} (${note})` : type);
Object.assign(state, {
layername,
share,
stock,
tool,
zBottom,

View file

@ -420,6 +420,18 @@ const dispatch = {
send.done({});
},
slicePre(data, send) {
const { settings } = data;
const { mode } = settings;
const driver = drivers[mode];
if (driver.slicePre) {
driver.slicePre(settings);
}
send.done();
},
slice(data, send) {
send.data({ update:0.001, updateStatus:"slicing" });