checkpoint roughing refactor

This commit is contained in:
Stewart Allen 2020-11-03 21:43:06 -05:00
commit 53d75fd4ed
4 changed files with 119 additions and 107 deletions

View file

@ -1286,7 +1286,7 @@
* @param {Polygon} poly * @param {Polygon} poly
* @returns {?Polygon} intersected polygon or null if no intersection * @returns {?Polygon} intersected polygon or null if no intersection
*/ */
PRO.union = function(poly, min) { PRO.union = function(poly, min, all) {
if (!this.overlaps(poly)) return null; if (!this.overlaps(poly)) return null;
let fillang = this.fillang && this.area() > poly.area() ? this.fillang : poly.fillang, let fillang = this.fillang && this.area() > poly.area() ? this.fillang : poly.fillang,
@ -1305,10 +1305,15 @@
if (clip.Execute(ctyp.ctUnion, ctre, cfil.pftEvenOdd, cfil.pftEvenOdd)) { if (clip.Execute(ctyp.ctUnion, ctre, cfil.pftEvenOdd, cfil.pftEvenOdd)) {
let union = POLY().fromClipperTreeUnion(ctre, poly.getZ(), minarea); let union = POLY().fromClipperTreeUnion(ctre, poly.getZ(), minarea);
if (all) {
return union;
}
if (union.length === 1) { if (union.length === 1) {
union = union[0]; union = union[0];
union.fillang = fillang; union.fillang = fillang;
return union; return union;
} else {
console.log({check_union_call_path: union});
} }
} }

View file

@ -31,6 +31,7 @@
union : union, union : union,
nest : nest, nest : nest,
diff : doDiff, diff : doDiff,
setZ : setZ,
filter : filter, filter : filter,
toClipper : toClipper, toClipper : toClipper,
fromClipperNode : fromClipperNode, fromClipperNode : fromClipperNode,
@ -49,6 +50,11 @@
return num !== undefined ? num : def; return num !== undefined ? num : def;
} }
function setZ(polys, z) {
polys.forEach(p => p.setZ(z));
return polys;
}
function toClipper(polys,debug) { function toClipper(polys,debug) {
let out = []; let out = [];
polys.forEach(function(poly) { poly.toClipper(out,debug) }); polys.forEach(function(poly) { poly.toClipper(out,debug) });
@ -336,7 +342,7 @@
* @param {Polygon[]} polys * @param {Polygon[]} polys
* @returns {Polygon[]} * @returns {Polygon[]}
*/ */
function union(polys, minarea) { function union(polys, minarea, all) {
if (polys.length < 2) return polys; if (polys.length < 2) return polys;
let out = polys.slice(), i, j, union, uset = []; let out = polys.slice(), i, j, union, uset = [];
@ -345,11 +351,15 @@
if (!out[i]) continue; if (!out[i]) continue;
for (j=i+1; j<out.length; j++) { for (j=i+1; j<out.length; j++) {
if (!out[j]) continue; if (!out[j]) continue;
union = out[i].union(out[j], minarea); union = out[i].union(out[j], minarea, all);
if (union) { if (union) {
out[i] = null; out[i] = null;
out[j] = null; out[j] = null;
out.push(union); if (all) {
out.appendAll(union);
} else {
out.push(union);
}
continue outer; continue outer;
} }
} }
@ -455,7 +465,7 @@
* and return resulting gaps from offsets for thin wall detection in * and return resulting gaps from offsets for thin wall detection in
* in FDM mode and uncleared areas in CAM mode. * in FDM mode and uncleared areas in CAM mode.
*/ */
function offset(polys, dist, opt) { function offset(polys, dist, options) {
// cause inner / outer polys to be reversed from each other // cause inner / outer polys to be reversed from each other
alignWindings(polys); alignWindings(polys);
polys.forEach(function(poly) { polys.forEach(function(poly) {
@ -465,9 +475,9 @@
}); });
let orig = polys, let orig = polys,
opts = opt || {}, opts = options || {},
count = numOrDefault(opt.count, 1), count = numOrDefault(opts.count, 1),
depth = numOrDefault(opt.depth, 0), depth = numOrDefault(opts.depth, 0),
clean = opts.clean !== false, clean = opts.clean !== false,
simple = opts.simple !== false, simple = opts.simple !== false,
fill = opts.fill || ClipperLib.PolyFillType.pftNonZero, fill = opts.fill || ClipperLib.PolyFillType.pftNonZero,
@ -478,7 +488,7 @@
// if dist is array with values, shift out next offset // if dist is array with values, shift out next offset
offs = Array.isArray(dist) ? (dist.length > 1 ? dist.shift() : dist[0]) : dist, offs = Array.isArray(dist) ? (dist.length > 1 ? dist.shift() : dist[0]) : dist,
mina = numOrDefault(opts.minArea, 0.1), mina = numOrDefault(opts.minArea, 0.1),
zed = opt.z || 0; zed = opts.z || 0;
// setup offset // setup offset
polys.forEach(function(poly) { polys.forEach(function(poly) {
@ -494,45 +504,41 @@
polys = fromClipperTree(ctre, zed, null, null, mina); polys = fromClipperTree(ctre, zed, null, null, mina);
// if specified, perform offset gap analysis // if specified, perform offset gap analysis
if (opt.gaps && polys.length) { if (opts.gaps && polys.length) {
let oneg = offset(polys, -offs, { let oneg = offset(polys, -offs, {
fill: opt.fill, join: opt.join, type: opt.type, z: opt.z, minArea: mina fill: opts.fill, join: opts.join, type: opts.type, z: opts.z, minArea: mina
}); });
let suba = []; let suba = [];
let diff = subtract(orig, oneg, suba, null, zed); let diff = subtract(orig, oneg, suba, null, zed);
opt.gaps.append(suba, opt.flat); opts.gaps.append(suba, opts.flat);
} }
// if offset fails, consider last polygons as gap areas // if offset fails, consider last polygons as gap areas
if (opt.gaps && !polys.length) { if (opts.gaps && !polys.length) {
opt.gaps.append(orig, opt.flat); opts.gaps.append(orig, opts.flat);
} }
// if specified, perform up to *count* successive offsets // if specified, perform up to *count* successive offsets
if (polys.length) { if (polys.length) {
// ensure opts has offset accumulator array // ensure opts has offset accumulator array
opt.outs = opt.outs || []; opts.outs = opts.outs || [];
// store polys in accumulator // store polys in accumulator
opt.outs.append(polys, opt.flat); opts.outs.append(polys, opts.flat);
// callback for expand() compatibility // callback for expand() compatibility
if (opt.call) { if (opts.call) {
opt.call(polys, count, depth); opts.call(polys, count, depth);
} }
// check for more offsets // check for more offsets
if (count > 1) { if (count > 1) {
// decrement count, increment depth // decrement count, increment depth
opt.count = count - 1; opts.count = count - 1;
opt.depth = depth + 1; opts.depth = depth + 1;
// call next offset // call next offset
offset(polys, dist, opt); offset(polys, dist, opts);
// } else if (count === 0) {
// // depth = 0 means offset until failure
// opt.depth = depth + 1;
// offset(polys, dist, opt);
} }
} }
return opt.flat ? opt.outs : polys; return opts.flat ? opts.outs : polys;
} }
/** /**

View file

@ -180,12 +180,19 @@
return rarr; return rarr;
} }
let phash = {}, let znorm = z.toFixed(5),
flatoff = opt.flatoff || 0.007,
onflat = this.zFlat[znorm],
phash = {},
lines = [], lines = [],
zScale = this.zScale, zScale = this.zScale,
buckets = this.buckets, buckets = this.buckets,
bucket = buckets.length ? buckets[Math.floor(z * zScale)] : points; bucket = buckets.length ? buckets[Math.floor(z * zScale)] : points;
if (onflat) {
z += flatoff;
}
if (!bucket) { if (!bucket) {
console.log({no_bucket_for_z: z}); console.log({no_bucket_for_z: z});
return; return;
@ -236,7 +243,7 @@
} }
} }
if (opt.each) { if (opt.each && (lines.length || opt.emptyok)) {
opt.each(retn, index, total, UTIL.time() - mark); opt.each(retn, index, total, UTIL.time() - mark);
} }

View file

@ -288,7 +288,6 @@
let out = []; let out = [];
POLY.expand(last, -offset*1.1, 0, out, 1); POLY.expand(last, -offset*1.1, 0, out, 1);
return out; return out;
} }
@ -667,50 +666,31 @@
* @param {Polygon[]} shell enclosing slice tops * @param {Polygon[]} shell enclosing slice tops
* @param {number} diameter of tool (mm) * @param {number} diameter of tool (mm)
* @param {number} stock to leave (mm) * @param {number} stock to leave (mm)
* @param {number} percent overlap on each pass * @param {number} overlap on each pass
* @param {boolean} widecut expand outer cutout
* @returns {Object} shell or newly generated shell
*/ */
function createRoughPaths(slice, shell, diameter, stock, overlap, holes) { function createRoughPaths(slice, shell, diameter, stock, overlap) {
let tops = slice.gatherTopPolys([]).clone(true), let tops = slice.shadow;
outer = [], let offset = [shell.clone(true),tops.clone(true)].flat();
offset = []; let flat = POLY.flatten(offset, [], true);
// when thru holes present, treat them as top offsets offset = POLY.setZ(POLY.nest(flat), slice.z);
// to prevent roughing out the entire hole // slice.tops[0].inner = offset;
if (holes) {
tops.appendAll(holes);
}
// clone and flatten the shell with tops to offset array
shell.clone(true).forEach(function(poly) {
poly.setZ(slice.z).flattenTo(offset);
});
POLY.flatten(tops, offset, true);
// only tab cut polys should be open (happens later)
offset.forEach(function(trace) {
trace.setClosed();
});
// re-nest offset array
offset = POLY.nest(offset);
// inset offset array by 1/2 diameter then by tool overlap % // inset offset array by 1/2 diameter then by tool overlap %
slice.tops[0].traces =
POLY.offset(offset, [-(diameter / 2 + stock), -diameter * overlap], { POLY.offset(offset, [-(diameter / 2 + stock), -diameter * overlap], {
z: slice.z, z: slice.z,
count: 999, count: 999,
flat: true, flat: true,
outs: outer,
call: (polys, count, depth) => { call: (polys, count, depth) => {
polys.forEach(p => { polys.forEach(p => {
p.depth = depth; p.depth = depth;
if (p.inner) p.inner.forEach(p => p.depth = depth); if (p.inner) {
p.inner.forEach(p => p.depth = depth);
}
}); });
} }
}); });
slice.tops[0].traces = outer;
}; };
/** /**
@ -853,7 +833,7 @@
roughToolDiam = getToolDiameter(conf, proc.camRoughTool), roughToolDiam = getToolDiameter(conf, proc.camRoughTool),
outlineToolDiam = getToolDiameter(conf, proc.camOutlineTool), outlineToolDiam = getToolDiameter(conf, proc.camOutlineTool),
contourToolDiam = getToolDiameter(conf, proc.camContourTool), contourToolDiam = getToolDiameter(conf, proc.camContourTool),
procFacing = proc.camRoughOn && proc.camZTopOffset, procFacing = false && proc.camRoughOn && proc.camZTopOffset,
procRough = proc.camRoughOn && proc.camRoughDown && roughToolDiam, procRough = proc.camRoughOn && proc.camRoughDown && roughToolDiam,
procOutlineIn = proc.camOutlineIn, procOutlineIn = proc.camOutlineIn,
procOutlineOut = proc.camOutlineOut, procOutlineOut = proc.camOutlineOut,
@ -1002,7 +982,7 @@
}); });
// set all default shells // set all default shells
const camShellPolys = shellRough = shellOutline = facePolys = camShell.gatherTopPolys([]); const camShellPolys = shellOutline = facePolys = camShell.gatherTopPolys([]);
if (procDrillReg) { if (procDrillReg) {
sliceDrillReg(settings, widget, sliceAll, zThru); sliceDrillReg(settings, widget, sliceAll, zThru);
@ -1012,11 +992,6 @@
sliceDrill(settings, widget, slices, sliceAll); sliceDrill(settings, widget, slices, sliceAll);
} }
if (procRough) {
// expand shell by half tool diameter + stock to leave
shellRough = facePolys = POLY.expand(shellRough, (roughToolDiam / 2) + camRoughStock, 0);
}
if (procOutline) { if (procOutline) {
if (!procOutlineOut) { if (!procOutlineOut) {
// expand shell minimally triggering a clean // expand shell minimally triggering a clean
@ -1048,18 +1023,6 @@
} }
} }
if (procRough) {
let selected = [];
selectSlices(slices, camRoughDown * units, CPRO.ROUGH, selected);
if (zThru) {
addZThru(selected);
}
sliceAll.appendAll(selected);
if (!proc.camRoughVoid) {
thruHoles = holes(slices, roughToolDiam + camRoughStock);
}
}
if (procOutline) { if (procOutline) {
let selected = []; let selected = [];
selectSlices(slices, proc.camOutlineDown * units, CPRO.OUTLINE, selected); selectSlices(slices, proc.camOutlineDown * units, CPRO.OUTLINE, selected);
@ -1069,32 +1032,62 @@
sliceAll.appendAll(selected); sliceAll.appendAll(selected);
} }
} }
/*
let slicer = new KIRI.slicer2(widget.getPoints(), { let slicer = new KIRI.slicer2(widget.getPoints(), {
zlist: true, zlist: true,
zline: true, zline: true
genso: true // generate slice object
}); });
let zindex = slicer.interval(1, { down: true }); let tshadow = [];
let terrain = slicer.slice(zindex, { each: (data, index, total) => { let tzindex = slicer.interval(1); // bottom up
let terrain = slicer.slice(tzindex, { each: (data, index, total) => {
console.log('terrain', index, total, data); console.log('terrain', index, total, data);
tshadow = POLY.union(tshadow.appendAll(data.tops), 0.01, true);
} }); } });
let shadow = []; console.log({slicer, tzindex, tshadow, terrain});
// shadow generation bottom-up is faster
terrain.reverse().forEach(data => { // do creating roughing slices
if (data.tops) { if (procRough) {
shadow = POLY.union(shadow.appendAll(data.tops)); // identify through holes
} thruHoles = tshadow.map(p => p.inner || []).flat();
});
console.log({slicer, zindex, shadow, terrain}); let shadow = [];
let slices = [];
slicer.slice(slicer.interval(roughDown, { down: true }), { each: (data, index, total) => {
shadow = POLY.union(shadow.appendAll(data.tops), 0.01, true);
data.shadow = shadow.clone(true);
data.slice.camMode = CPRO.ROUGH;
data.slice.shadow = data.shadow;
slices.push(data.slice);
}, genso: true });
// inset or eliminate thru holes from shadow
shadow = POLY.flatten(shadow.clone(true), [], true);
thruHoles.forEach(hole => {
shadow = shadow.map(p => {
if (p.isEquivalent(hole)) {
// eliminate thru holes when roughing voids enabled
if (proc.camRoughVoid) {
return undefined;
}
let po = POLY.offset([p], -(roughToolDiam + camRoughStock));
return po ? po[0] : undefined;
} else {
return p;
}
}).filter(p => p);
});
shadow = POLY.nest(shadow);
// expand shadow by half tool diameter + stock to leave
shellRough = POLY.offset(shadow, (roughToolDiam / 4) + camRoughStock);
if (zThru) {
addZThru(slices);
}
sliceAll.appendAll(slices);
}
// do roughing slices
if (procRough)
slicer.slice(slicer.interval(roughDown, { down: true }), { each: (data, index, total) => {
// annotate slice
console.log('rough', data.z, data);
} });
*/
// horizontal slices for rough/outline // horizontal slices for rough/outline
doSlicing(widget, {height:sliceDepth, cam:true, zmin:zBottom, noEmpty:true}, camSlicesDone, function(update) { doSlicing(widget, {height:sliceDepth, cam:true, zmin:zBottom, noEmpty:true}, camSlicesDone, function(update) {
onupdate(0.0 + update * 0.25, "slicing"); onupdate(0.0 + update * 0.25, "slicing");
@ -1103,15 +1096,15 @@
// we need topo for safe travel moves when roughing and outlining // we need topo for safe travel moves when roughing and outlining
// not generated when drilling-only. then all z moves use bounds max. // not generated when drilling-only. then all z moves use bounds max.
// also generates x and y contouring when selected // also generates x and y contouring when selected
if (procRough || procOutline || procContour) // if (procRough || procOutline || procContour)
generateTopoMap(widget, settings, function(slices) { // generateTopoMap(widget, settings, function(slices) {
sliceAll.appendAll(slices); // sliceAll.appendAll(slices);
// todo union rough / outline shells // // todo union rough / outline shells
// todo union rough / outline tabs // // todo union rough / outline tabs
// todo append to generated topo map // // todo append to generated topo map
}, function(update, msg) { // }, function(update, msg) {
onupdate(0.40 + update * 0.50, msg || "create topo"); // onupdate(0.40 + update * 0.50, msg || "create topo");
}); // });
// prepare for tracing paths // prepare for tracing paths
let traceTool; let traceTool;
@ -1253,7 +1246,8 @@
tops.forEach(function(top) { tops.forEach(function(top) {
outline.poly(top.poly, 0x999900, true, open); outline.poly(top.poly, 0x999900, true, open);
if (top.inner) outline.poly(top.inner, 0xdddddd, true); // if (top.inner) outline.poly(top.inner, 0xdddddd, true);
if (top.inner) outline.poly(top.inner, 0xff0000, true);
}); });
// various outlining // various outlining