fix open polys with area trace

This commit is contained in:
Stewart Allen 2025-12-13 21:15:00 -05:00
commit 1824fc4522
6 changed files with 50 additions and 28 deletions

View file

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

View file

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

View file

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

View file

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

View file

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