fix numerous bounds issues with indexed stock fixes #340

fix state variable updates with indexex stock
fix large tool animation fixes #352
This commit is contained in:
Stewart Allen 2025-06-22 22:09:02 -04:00
commit 7b1f230ded
7 changed files with 104 additions and 72 deletions

View file

@ -540,7 +540,7 @@ kiri.load(() => {
const sd = Math.sqrt(mx*mx + my*my + Math.min(1,mz*mz) + dr*dr);
const moves = [];
for (let i=0, x=lp.x, y=lp.y, z=lp.z; i<st; i++) {
moves.push({x,y,z,a:lp.a,md:sd});
moves.push({ x, y, z, a:lp.a, md:sd, dx, dy, dz });
x += mx;
y += my;
z += mz;
@ -563,9 +563,11 @@ kiri.load(() => {
if (!pos) {
throw `no pos @ ${index} of ${moves.length}`;
}
const { dx, dy, dz } = pos;
toolMove(pos);
// console.log('renderMoves', {id, moves, seed});
let subs = 0;
if (dx || dy || dz < 0)
for (let slice of stockSlices) {
if (slice.bounds.intersectsBox(toolMesh.bounds)) {
slice.subtractTool(toolMesh);

View file

@ -474,13 +474,11 @@ CAM.init = function(kiri, api) {
return;
}
let index = 0;
let indexing = false;
for (let op of oplist) {
if (op.type === '|') {
break;
}
if (op.type === 'index' && !op.disabled) {
indexing = true;
if (op.absolute) {
index = op.degrees
} else {
@ -2190,6 +2188,8 @@ function updateStock() {
return;
}
api.platform.update_bounds();
const settings = API.conf.get();
const widgets = API.widgets.all();
@ -2197,9 +2197,13 @@ function updateStock() {
const { x, y, z, center } = stock;
UI.func.animate.classList.add('disabled');
if (camStock) {
SPACE.world.remove(camStock);
camStock = null;
}
if (x && y && z) {
UI.func.animate.classList.remove('disabled');
if (!camStock) {
{
let geo = new THREE.BoxGeometry(1, 1, 1);
let mat = new THREE.MeshBasicMaterial({
color: 0x777777,
@ -2231,21 +2235,17 @@ function updateStock() {
let lines = new THREE.LineSegments(ligeo, limat);
camStock.lines = lines;
camStock.add(lines);
SPACE.world.add(camStock);
}
// fight z fighting in threejs
camStock.scale.x = x + 0.005;
camStock.scale.y = y + 0.005;
camStock.scale.z = z + 0.005;
camStock.position.x = center.x;
camStock.position.y = center.y;
camStock.position.z = center.z;
camStock.rotation.x = currentIndex || 0;
camStock.lines.material.color =
new THREE.Color(isDark() ? 0x555555 : 0xaaaaaa);
} else if (camStock) {
SPACE.world.remove(camStock);
camStock = null;
}
SPACE.world.remove(camZTop);

View file

@ -45,12 +45,17 @@ class OpIndex extends CamOp {
super(state, op);
}
slice() {
async slice() {
let { op, state } = this;
if (!state.isIndexed) {
throw 'index op requires indexed stock';
}
this.degrees = state.setAxisIndex(op.degrees, op.absolute);
let { widget, updateSlicer, computeShadows, setAxisIndex } = state;
this.degrees = setAxisIndex(op.degrees, op.absolute);
// force recompute of topo
widget.topo = undefined;
updateSlicer();
await computeShadows();
}
prepare(ops, progress) {
@ -483,8 +488,7 @@ class OpOutline extends CamOp {
async slice(progress) {
let { op, state } = this;
let { settings, widget, slicer, addSlices, tshadow, thruHoles, unsafe, color } = state;
let { updateToolDiams, tabs, cutTabs, cutPolys, workarea } = state;
let { zMax } = state;
let { updateToolDiams, tabs, cutTabs, cutPolys, workarea, zMax } = state;
let { process, stock } = settings;
if (op.down <= 0) {

View file

@ -32,7 +32,6 @@ const POLY = polygons;
CAM.slice = async function(settings, widget, onupdate, ondone) {
let proc = settings.process,
sliceAll = widget.slices = [],
// slices = widget.slices = [],
camOps = widget.camops = [],
isIndexed = proc.camStockIndexed;
@ -48,8 +47,17 @@ CAM.slice = async function(settings, widget, onupdate, ondone) {
// allow recomputing later if widget or settings changes
const var_compute = () => {
stock = settings.stock || {};
let { camStockX, camStockY, camStockZ, camStockOffset } = proc;
bounds = widget.getBoundingBox();
stock = camStockOffset ? {
x: bounds.dim.x + camStockX,
y: bounds.dim.y + camStockY,
z: bounds.dim.z + camStockZ,
} : {
x: camStockX,
y: camStockY,
z: camStockZ
}
track = widget.track;
({ camZTop, camZBottom, camZThru } = proc);
wztop = track.top;
@ -73,7 +81,7 @@ CAM.slice = async function(settings, widget, onupdate, ondone) {
bottom_part = 0;
bottom_stock = -bottom_gap;
bottom_thru = zThru;
bottom_z = Math.max(
bottom_z = isIndexed ? zBottom : Math.max(
(camZBottom ? bottom_stock + camZBottom : bottom_part) - bottom_thru,
(camZBottom ? bottom_stock + camZBottom : bottom_stock - bottom_thru)
);
@ -145,15 +153,55 @@ CAM.slice = async function(settings, widget, onupdate, ondone) {
}
let mark = Date.now();
let slicer = new kiri.cam_slicer(widget);
let opList = [];
let opSum = 0;
let opTot = 0;
let shadows = {};
let slicer;
let state = {
settings,
widget,
bounds,
tabs,
cutTabs,
cutPolys,
healPolys,
shadowAt,
slicer,
addSlices,
isIndexed,
setAxisIndex,
updateToolDiams,
updateSlicer,
computeShadows,
zBottom,
zThru,
ztOff,
zMax,
zTop,
unsafe,
color,
dark,
ops: opList
};
let tracker = setSliceTracker({ rotation: 0 });
function updateSlicer() {
slicer = state.slicer = new kiri.cam_slicer(widget);
}
async function computeShadows() {
shadows = {};
await new CAM.OPS.shadow(state, { type: "shadow", silent: true }).slice(progress => {
// console.log('reshadow', progress.round(3));
});
}
function updateToolDiams(toolDiam) {
minToolDiam = Math.min(minToolDiam, toolDiam);
maxToolDiam = Math.max(maxToolDiam, toolDiam);
}
let shadows = {};
function shadowAt(z) {
let cached = shadows[z];
if (cached) {
@ -216,44 +264,22 @@ CAM.slice = async function(settings, widget, onupdate, ondone) {
}
}
let state = {
settings,
widget,
bounds,
tabs,
cutTabs,
cutPolys,
healPolys,
shadowAt,
slicer,
addSlices,
isIndexed,
setAxisIndex,
updateToolDiams,
zBottom,
zThru,
ztOff,
zMax,
zTop,
unsafe,
color,
dark,
};
let opList = [
// silently preface op list with OpShadow
new CAM.OPS.shadow(state, { type: "shadow", silent: true })
];
if (false) {
opList.push(new CAM.OPS.xray(state, { type: "xray" }));
}
let opSum = 0;
let opTot = opList.length ? opList.map(op => op.weight()).reduce((a,v) => a + v) : 0;
let activeOps = proc.ops.filter(op => !op.disabled);
// silently preface op list with OpShadow
if (isIndexed) {
if (activeOps.length === 0 || activeOps[0].type !== 'index')
opList.push(new CAM.OPS.index(state, { type: "index", index: 0 }));
} else {
opList.push(new CAM.OPS.shadow(state, { type: "shadow", silent: true }));
}
// determing # of steps and step weighting for progress bar
for (let op of proc.ops.filter(op => !op.disabled)) {
for (let op of activeOps) {
if (op.type === '|') {
break;
}
@ -265,39 +291,41 @@ CAM.slice = async function(settings, widget, onupdate, ondone) {
}
}
// give ops access to entire sequence
state.ops = opList;
// call slice() function on all ops in order
let tracker = setSliceTracker({ rotation: 0 });
setAxisIndex();
updateSlicer();
for (let op of opList) {
let weight = op.weight();
// apply operation override vars
let workover = var_compute();
let valz = op.op;
if (valz.ov_topz) {
workover.top_z = bottom_stock + valz.ov_topz;
workover.top_z = isIndexed ? valz.ov_topz : bottom_stock + valz.ov_topz;
}
if (valz.ov_botz) {
workover.bottom_z = bottom_stock + valz.ov_botz;
workover.bottom_z = isIndexed ? valz.ov_botz : bottom_stock + valz.ov_botz;
workover.bottom_cut = Math.max(workover.bottom_z, -zThru);
}
state.workarea = workover;
// state.workarea = workover;
Object.assign(state, {
zBottom,
zThru,
ztOff,
zMax,
zTop,
workarea: workover
});
// console.log({
// op,
// workover,
// bounds: structuredClone(bounds),
// stock: structuredClone(stock)
// });
await op.slice((progress, message) => {
onupdate((opSum + (progress * weight)) / opTot, message || op.type());
});
// update tracker rotation for next slice output() visualization
tracker.rotation = isIndexed ? axisRotation : 0;
// setup new state when indexing the workspace
if (op.op.type === "index") {
widget.topo = undefined;
// let points = base.verticesToPoints();
slicer = state.slicer = new kiri.cam_slicer(widget);
shadows = {};
await new CAM.OPS.shadow(state, { type: "shadow", silent: true }).slice(progress => {
// console.log('reshadow', progress.round(3));
});
}
camOps.push(op);
opSum += weight;
}

View file

@ -137,7 +137,7 @@ class Tool {
drill_tip_length = this.drillTipLength(),
shaft_offset = this.fluteLength(),
flute_diameter = this.fluteDiameter(),
shaft_diameter = this.shaftDiameter(),
shaft_diameter = Math.max(flute_diameter, this.shaftDiameter()),
max_diameter = Math.max(flute_diameter, shaft_diameter),
shaft_pix_float = max_diameter / resolution,
shaft_pix_int = Math.round(shaft_pix_float),

View file

@ -7,11 +7,8 @@
gapp.register("kiri.slice", [], (root, exports) => {
const { base, kiri } = root;
const { key, polygons } = base;
const { util } = base;
const POLY = base.polygons;
const NOKEY = key.NONE;
let tracker;

View file

@ -472,6 +472,7 @@ class Widget {
let rad = deg * (Math.PI / 180);
if (rad !== this.track.indexRad) {
this.track.indexRad = rad;
this.setModified();
this._updateMeshPosition();
}
}