From 1824fc452205492ace24dd5ad73f1f16a64a3ff6 Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Sat, 13 Dec 2025 21:15:00 -0500 Subject: [PATCH] fix open polys with area trace --- src/geo/polygon.js | 24 ++++++++++++++++-------- src/geo/polygons.js | 1 + src/kiri/mode/cam/cl-trace.js | 2 +- src/kiri/mode/cam/op-area.js | 28 +++++++++++++++++++--------- src/kiri/mode/cam/prepare.js | 19 +++++++++++-------- web/kiri/index.html | 4 ++-- 6 files changed, 50 insertions(+), 28 deletions(-) diff --git a/src/geo/polygon.js b/src/geo/polygon.js index 9f15285f..1bb4bbbe 100644 --- a/src/geo/polygon.js +++ b/src/geo/polygon.js @@ -2013,14 +2013,22 @@ export class Polygon { closest, mindist = Infinity; - this.forEachPoint((point, pos) => { - dist = Math.sqrt(point.distToSq2D(target)); - if (dist < mindist) { - index = pos; - mindist = dist; - closest = point; - } - }); + if (this.open) { + let d0 = target.distTo2D(this.first()); + let d1 = target.distTo2D(this.last()); + mindist = Math.min(d0, d1); + closest = d0 < d1 ? this.first() : this.last(); + index = d0 < d1 ? 0 : this.points.length - 1; + } else { + this.forEachPoint((point, pos) => { + dist = Math.sqrt(point.distToSq2D(target)); + if (dist < mindist) { + index = pos; + mindist = dist; + closest = point; + } + }); + } return { distance: mindist, diff --git a/src/geo/polygons.js b/src/geo/polygons.js index c92bcc34..7eadfb10 100644 --- a/src/geo/polygons.js +++ b/src/geo/polygons.js @@ -602,6 +602,7 @@ export function offset(polys, dist, opts = {}) { if (open.length) { open = open.map(p => paths.pointsToPath(p.points, Array.isArray(dist) ? dist[0] : dist, true)); open = open.map(p => newPolygon().setOpen().addPoints(p.right)); + if (opts.z) open.forEach(p => p.setZ(opts.z)); } // do not use clipper to offset open lines diff --git a/src/kiri/mode/cam/cl-trace.js b/src/kiri/mode/cam/cl-trace.js index 34ba3f0c..3af4e19d 100644 --- a/src/kiri/mode/cam/cl-trace.js +++ b/src/kiri/mode/cam/cl-trace.js @@ -86,7 +86,7 @@ export function traceDone() { env.func.unpop(); traceOn.classList.remove("editing"); traceOn = false; - api.widgets.opacity(1); + api.widgets.setOpacity(1); api.hide.alert(alert); api.feature.hover = false; api.feature.hoverAdds = false; diff --git a/src/kiri/mode/cam/op-area.js b/src/kiri/mode/cam/op-area.js index 442e9840..bc44382b 100644 --- a/src/kiri/mode/cam/op-area.js +++ b/src/kiri/mode/cam/op-area.js @@ -19,8 +19,6 @@ const ptyp = clib.PolyType; const cfil = clib.PolyFillType; const ts_eps = 0.01; -// todo: review tool_shadow. offset both directions for travel inside and outside / between? - class OpArea extends CamOp { constructor(state, op) { super(state, op); @@ -222,7 +220,7 @@ class OpArea extends CamOp { } else if (mode === 'trace') { let { tr_type } = op; - let zs = down ? base_util.lerp(zTop, zBottom, down) : [ bounds.min.z ]; + let zs = down ? base_util.lerp(zTop, area.minZ(), down) : [ bounds.min.z ]; let zroc = 0; let zinc = 1 / zs.length; for (let z of zs) { @@ -265,12 +263,16 @@ class OpArea extends CamOp { slice.camLines = outs; POLY.setWinding(outs, direction === 'climb'); // store travel boundary that triggers up and over moves - slice.tool_shadow = [ - area, - ...shadow, - ...POLY.offset(shadow, [ ts_off ], { count: 1, z, ...offopt }), - ...POLY.offset(shadow, [ -ts_off ], { count: 1, z, ...offopt }), - ]; + let tool_shadow = slice.tool_shadow = shadow; + if (area.isOpen()) { + tool_shadow.push(...outs[0].clone().setZ(z).offset_open(toolDiam / 2, 'round')); + } else { + tool_shadow.push( + area, + ...POLY.offset(shadow, [ ts_off ], { count: 1, z, ...offopt }), + ...POLY.offset(shadow, [ -ts_off ], { count: 1, z, ...offopt }), + ); + } // add tabs to travel boundaries if (tabs) { let tab_shadows = tabs.filter(t => t.top >= z).map(t => t.poly); @@ -278,6 +280,13 @@ class OpArea extends CamOp { } zroc += zinc; progress(proc + (pinc * zroc), 'trace'); + if (devel) layers + .setLayer("base", { line: 0xff0000 }, false) + .addPolys(shadowBase) + .setLayer("shadow", { line: 0x00ff00 }, false) + .addPolys(shadow) + .setLayer("tool shadow", { line: 0x44ff88 }, false) + .addPolys(tool_shadow); layers .setLayer(rename ?? "trace", { line: color }, false) .addPolys(outs); @@ -411,6 +420,7 @@ class OpArea extends CamOp { dist: Infinity, area: undefined }; + for (let area of areas.filter(p => !p.used)) { // skip devel / debug only areas let topPolys = area[0].camLines; diff --git a/src/kiri/mode/cam/prepare.js b/src/kiri/mode/cam/prepare.js index b61b5f19..2e5ddf8e 100644 --- a/src/kiri/mode/cam/prepare.js +++ b/src/kiri/mode/cam/prepare.js @@ -679,12 +679,15 @@ export async function prepare_one(widget, settings, print, firstPoint, update) { let arcing = camArcEnabled && !contouring; let points = poly.points; - if (index === CLOSEST_TO_PP) { - let found = poly.findClosestPointTo(getWidgetPrintPoint()); - index = found.index; - } - if (index) { - points = [...points.slice(index), ...points.slice(0,index)]; + if (poly.isClosed()) { + // only look for the cloests starting point for closed loops + if (index === CLOSEST_TO_PP) { + let found = poly.findClosestPointTo(getWidgetPrintPoint()); + index = found.index; + } + if (index) { + points = [...points.slice(index), ...points.slice(0,index)]; + } } if (!contouring && poly.isClosed()) { @@ -703,8 +706,8 @@ export async function prepare_one(widget, settings, print, firstPoint, update) { setNextIsMove(); - // we skip ease-down logic in contouring mode - if (!contouring && camEaseDown) { + // we skip ease-down logic in contouring mode or for open polys (traces .. maybe later) + if (!contouring && camEaseDown && poly.isClosed()) { let point0 = points[0]; // perform "up and over" and get a new printPoint without "emit" diff --git a/web/kiri/index.html b/web/kiri/index.html index 5de0fcfb..df7431f9 100644 --- a/web/kiri/index.html +++ b/web/kiri/index.html @@ -22,8 +22,8 @@ - - +