From f59a2ea0219becca061af4209f32d16f9b54e5bd Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Sun, 7 Dec 2025 21:37:34 -0500 Subject: [PATCH] add area to travel bounds, pump shadow for annealing, add input select post to allow name updates --- src/kiri/core/ui.js | 3 +++ src/kiri/core/widget.js | 5 +++++ src/kiri/mode/cam/cl-ops.js | 5 ++--- src/kiri/mode/cam/op-area.js | 24 +++++++++++++++--------- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/kiri/core/ui.js b/src/kiri/core/ui.js index 1078967d..cfe9e340 100644 --- a/src/kiri/core/ui.js +++ b/src/kiri/core/ui.js @@ -752,6 +752,9 @@ function newSelect(label, options = {}, source) { if (options.trigger) { refresh(); } + if (options.post) { + options.post(); + } }; ip.onclick = (ev) => { groupSticky = true; diff --git a/src/kiri/core/widget.js b/src/kiri/core/widget.js index c01f7308..7cba6cb5 100644 --- a/src/kiri/core/widget.js +++ b/src/kiri/core/widget.js @@ -946,6 +946,11 @@ class Widget { }); polys = POLY.union(polys, 0, true); + // for a more perfect union, pump shadows to merge very close lines + // todo: create clipper only version that avoids round trip thru geo classes + polys = POLY.offset(polys, 0.01); + polys = POLY.offset(polys, -0.01); + return polys; } } diff --git a/src/kiri/mode/cam/cl-ops.js b/src/kiri/mode/cam/cl-ops.js index c71c55e8..96a1d230 100644 --- a/src/kiri/mode/cam/cl-ops.js +++ b/src/kiri/mode/cam/cl-ops.js @@ -2,14 +2,13 @@ import { $, h } from '../../../moto/webui.js'; import { api } from '../../core/api.js'; -import { env } from './client.js'; +import { env, opRender } from './client.js'; import { Tool } from './tool.js'; import { opFlip } from './cl-flip.js'; import { selectHoles } from './cl-hole.js'; import { selectHelical } from './cl-helical.js'; import { surfaceAdd } from './cl-surface.js'; import { traceAdd } from './cl-trace.js'; -import { opRender } from './client.js'; const { MODES } = api.const; const { uc: UC } = api; @@ -682,7 +681,7 @@ export function createPopOps() { ov_botz: 0, direction: 'camAreaDirection', }).inputs = { - mode: UC.newSelect(LANG.mo_menu, {}, "opmode"), + mode: UC.newSelect(LANG.mo_menu, { post: opRender }, "opmode"), tr_type: UC.newSelect(LANG.cc_offs_s, { title: LANG.cc_offs_l, show: isTrace }, "traceoff"), sr_type: UC.newSelect("pattern", { title: "pattern", show: isSurface }, "surftyp"), sep: UC.newBlank({ class: "pop-sep" }), diff --git a/src/kiri/mode/cam/op-area.js b/src/kiri/mode/cam/op-area.js index bb39ef39..f57e52bc 100644 --- a/src/kiri/mode/cam/op-area.js +++ b/src/kiri/mode/cam/op-area.js @@ -17,6 +17,7 @@ const clib = self.ClipperLib; const ctyp = clib.ClipType; const ptyp = clib.PolyType; const cfil = clib.PolyFillType; +const ts_off = 0.1; class OpArea extends CamOp { constructor(state, op) { @@ -56,8 +57,8 @@ class OpArea extends CamOp { } } - function newLayer() { - stack.push(newSlice()); + function newLayer(z) { + stack.push(newSlice(z)); return stack.peek(); } @@ -132,12 +133,10 @@ class OpArea extends CamOp { let lzo; outer: for (;;) for (let z of zs) { - let slice = newLayer(); + let slice = newLayer(z); let layers = slice.output(); - let outs = []; - let clip = []; let shadow = await shadowAt(z); - let tool_shadow = POLY.offset(shadow, [ toolDiam / 2 - 0.01 ], { count: 1, z }); + let tool_shadow = POLY.offset(shadow, [ toolDiam / 2 - ts_off ], { count: 1, z }); // for roughing backward compatability if (op.omitthru) { shadow = shadow.clone(true); @@ -152,10 +151,14 @@ class OpArea extends CamOp { }); } } + // progressive offset of polygons inside area clipped to the shadow + let outs = []; + let clip = []; POLY.subtract([ area ], shadow, clip, undefined, undefined, 0); POLY.offset(clip, [ -toolDiam / 2, -toolOver ], { count: 999, outs, flat: true, z, minArea: 0 }); + // if we see no offsets, re-check the mesh bottom Z then exit if (outs.length === 0) { if (bounds && lzo > bounds.min.z) { // try a bottom layer matching bottom of selection @@ -174,10 +177,12 @@ class OpArea extends CamOp { for (let p of out) p.z += op.leave_z; } + // for roughing backward compatability if (op.leave_xy) { outs = outs.map(poly => poly.offset(-op.leave_xy)).flat(); } - slice.tool_shadow = tool_shadow; + // store travel boundary that triggers up and over moves + slice.tool_shadow = [ area, ...tool_shadow ]; slice.camLines = outs; zroc += zinc; lzo = z; @@ -206,7 +211,7 @@ class OpArea extends CamOp { let zroc = 0; let zinc = 1 / zs.length; for (let z of zs) { - let slice = newLayer(); + let slice = newLayer(z); let layers = slice.output(); let outs = []; if (tr_type === 'none') { @@ -228,7 +233,8 @@ class OpArea extends CamOp { // cut tabs when present if (tabs) outs = cutTabs(tabs, outs); slice.camLines = outs; - slice.tool_shadow = POLY.offset(await shadowAt(z), [ toolDiam / 2 - 0.01 ], { count: 1, z }); + // store travel boundary that triggers up and over moves + slice.tool_shadow = [ area, ...POLY.offset(await shadowAt(z), [ toolDiam / 2 - ts_off ], { count: 1, z }) ]; zroc += zinc; progress(proc + (pinc * zroc), 'trace'); layers