checkpoint poly arc finding (for drilling op upgrade)

This commit is contained in:
Stewart Allen 2024-07-02 13:28:13 -04:00
commit 9f14ecf88a
3 changed files with 99 additions and 15 deletions

View file

@ -109,6 +109,13 @@ function sqr(v) {
return v * v return v * v
} }
/**
* return distance between two points
*/
function dist2D(p1, p2) {
return Math.sqrt(distSq(p1, p2));
}
/** /**
* return distance squared between two points * return distance squared between two points
*/ */
@ -569,6 +576,7 @@ base.util = {
pwait, pwait,
ptimer, ptimer,
flatten, flatten,
dist2D,
distSq, distSq,
distSqv2, distSqv2,
center2d, center2d,
@ -577,6 +585,7 @@ base.util = {
orderClosest, orderClosest,
doCombinations, doCombinations,
offsetPrecision, offsetPrecision,
circleCenter,
numOrDefault, numOrDefault,
thetaDiff, thetaDiff,
intersect, intersect,

View file

@ -601,18 +601,20 @@ class Polygon {
} }
/** /**
* using perimeter length, find 3 equally spaced points to
* return a more accruate center point.
* @returns {Point} center of a polygon assuming it's a circle * @returns {Point} center of a polygon assuming it's a circle
*/ */
circleCenter() { calcCircleCenter() {
let pe = this.perimeter(), let pe = this.perimeter(),
pe1 = pe / 3, pe1 = pe / 3, // point 2
pe2 = pe1 * 2, pe2 = pe1 * 2, // point 3
p = this.points, p = this.points,
l = p.length, l = p.length,
i = 1, i = 1,
td = 0, td = 0,
lp = p[0], lp = p[0], // first point
ap = [ lp ]; ap = [ lp ]; // array of 3 points
while (i < l) { while (i < l) {
let np = p[i++]; let np = p[i++];
let d = lp.distTo2D(np); let d = lp.distTo2D(np);
@ -629,6 +631,67 @@ class Polygon {
return newPoint(center.x, center.y, p[0].z, null); return newPoint(center.x, center.y, p[0].z, null);
} }
/**
* iterate over poly points and find sequences of 5 or more points
* with a common center point and collect as a midpoint/radius
*/
findArcCenters(opt = {}) {
if (this.length < 6) return [];
let tolerance = opt.tolerance || 1e-2,
inside = opt.inside ?? true,
seq = this.points.slice(),
util = base.util;
if (this.isClosed()) seq.appendAll(seq.slice(0,5));
let recs = [], // accumulated arc points
cand = []; // candidate center array
for (let pos=3; pos<seq.length; pos++) {
let next = util.circleCenter(...seq.slice(pos-3, pos));
let prev = cand.peek();
if (inside && !newPoint(next.x,next.y).inPolygon(this)) {
// require point be inside current polygon
next = null;
}
// console.log({ pos, next, prev, cand });
if (next && !prev) {
// seed candidate list
cand.push(next);
continue;
}
if (!next) {
// next is a bust, reset candidate list
cand.length = 0;
continue;
}
// const dist = util.dist2D(next,prev);
// console.log({ dist: dist.round(6) });
if (util.dist2D(next,prev) < tolerance) {
// add new candidate
cand.push(next);
continue;
} else if (cand.length >= 3) {
// emit record on 5 points
recs.push(cand.peek());
}
// reset candidate array
cand = [ next ];
}
if (cand.length >= 3) {
recs.push(cand.peek());
}
// filter dups
recs.sort((a,b) => {
return util.dist2D(a,b);
});
recs = recs.filter((r,i) => {
if (i > 0) {
return util.dist2D(r, recs[i-1]) < tolerance*10 ? null : r;
} else {
return r;
}
});
return recs;
}
/** /**
* add points forming a rectangle around a center point * add points forming a rectangle around a center point
* *

View file

@ -1418,31 +1418,43 @@ class OpDrill extends CamOp {
// for each slice, look for polygons with 98.5% circularity whose // for each slice, look for polygons with 98.5% circularity whose
// area is within the tolerance of a circle matching the tool diameter // area is within the tolerance of a circle matching the tool diameter
tslices.forEach(function(slice) { for (let slice of tslices) {
if (slice.z < zBottom) return; if (slice.z < zBottom) {
continue;
}
let inner = slice.topPolyInners([]); let inner = slice.topPolyInners([]);
inner.forEach(function(poly) { for (let poly of inner) {
if (poly.circularity() >= 0.985 && Math.abs(poly.area() - area) <= areaDelta) { if (poly.circularity() >= 0.985 && Math.abs(poly.area() - area) <= areaDelta) {
let center = poly.circleCenter(), let center = poly.calcCircleCenter(),
merged = false, merged = false,
closest = Infinity, closest = Infinity,
dist; dist;
// TODO reject if inside camShellPolys (means there is material above) // TODO reject if inside camShellPolys (means there is material above)
if (center.isInPolygon(slice.shadow)) return; if (center.isInPolygon(slice.shadow)) {
drills.forEach(function(drill) { continue;
if (merged) return; }
for (let drill of drills) {
if (merged) {
continue;
}
if ((dist = drill.last().distTo2D(center)) <= centerDiff) { if ((dist = drill.last().distTo2D(center)) <= centerDiff) {
merged = true; merged = true;
drill.push(center); drill.push(center);
} }
closest = Math.min(closest,dist); closest = Math.min(closest,dist);
}); }
if (!merged) { if (!merged) {
drills.push(newPolygon().append(center)); drills.push(newPolygon().append(center));
} }
} else if (op.arcs) {
// find arcs
let arcs = poly.findArcCenters();
for (let arc of arcs) {
drills.push(newPolygon().add(arc.x,arc.y,arc.z||0));
}
} }
}); }
}); }
// drill points to use center (average of all points) of the polygon // drill points to use center (average of all points) of the polygon
drills.forEach(function(drill) { drills.forEach(function(drill) {