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 @@
-
-
+