when healing enabled, warn when non-manifold geometry detected. update release notes

This commit is contained in:
Stewart Allen 2022-09-08 13:26:47 -04:00
commit 059dbced58
8 changed files with 62 additions and 14 deletions

View file

@ -79,6 +79,7 @@
* `F` add option for op-major ordering (instead of part major) * `F` add option for op-major ordering (instead of part major)
* `F` animate only selected range (as an option) * `F` animate only selected range (as an option)
* `F` add `plunge max` to contouring that can override z feed limit * `F` add `plunge max` to contouring that can override z feed limit
* `F` add ability to select regions for contouring op (like pocketing)
* `F` roughing flats should be constrained to flat region, not create a layer * `F` roughing flats should be constrained to flat region, not create a layer
* `F` limit cut depth to flute length of selected tool (or warn) * `F` limit cut depth to flute length of selected tool (or warn)
* `F` change color of line selection in trace op when not a closed poly * `F` change color of line selection in trace op when not a closed poly

View file

@ -7,6 +7,16 @@ Full docs @ https://docs.grid.space/projects/kiri-moto
## Kiri:moto ## Kiri:moto
* add support to run as Progressive Web Apps for installation and offline use
* add assembly import when KM used inside of Onshape
* add configurable flatness for contour clipping
* add axis label remapping in FDM
* extend url loading of workspaces to all formats
* alert when healing is enabled and non-manifold geometries are detected
* fix thin output start and end point tracking which broke retraction
* fix for importing with some obj formatting
* fix profile seeding for newer device record formats
* fix workspace import / restore for some file formats
* fix potential crash into stock during moves when parts are z bottom anchored * fix potential crash into stock during moves when parts are z bottom anchored
* ~ refactor vertex replacement and widget update matrix tracking * ~ refactor vertex replacement and widget update matrix tracking
* ~ refactor cnc to use core slicer engine * ~ refactor cnc to use core slicer engine

View file

@ -36,6 +36,7 @@ const POLYS = base.polygons = {
expand, expand,
expand_lines, expand_lines,
points, points,
length,
route, route,
union, union,
inset, inset,
@ -52,6 +53,14 @@ const POLYS = base.polygons = {
fingerprint fingerprint
}; };
function length(polys) {
let length = 0;
for (let p of polys) {
length += p.deepLength;
}
return length;
}
function setZ(polys, z) { function setZ(polys, z) {
for (let poly of polys) { for (let poly of polys) {
poly.setZ(z); poly.setZ(z);
@ -376,13 +385,16 @@ function subtract(setA, setB, outA, outB, z, minArea, opt = {}) {
*/ */
function union(polys, minarea, all, opt = {}) { function union(polys, minarea, all, opt = {}) {
if (polys.length < 2) return polys; if (polys.length < 2) return polys;
let lpre = length(polys);
if (opt.wasm && geo.wasm) { if (opt.wasm && geo.wasm) {
let min = minarea || 0.01; let min = minarea || 0.01;
// let deepLength = polys.map(p => p.deepLength).reduce((a,v) => a+v); // let deepLength = polys.map(p => p.deepLength).reduce((a,v) => a+v);
// if (deepLength < 15000) // if (deepLength < 15000)
try { try {
return geo.wasm.js.union(polys, polys[0].getZ()).filter(p => p.area() > min); let out = geo.wasm.js.union(polys, polys[0].getZ()).filter(p => p.area() > min);
opt.changes = length(out) - lpre;
return out;
} catch (e) { } catch (e) {
console.log({union_fail: polys, minarea, all}); console.log({union_fail: polys, minarea, all});
} }
@ -419,6 +431,7 @@ function subtract(setA, setB, outA, outB, z, minArea, opt = {}) {
if (out[i]) uset.push(out[i]); if (out[i]) uset.push(out[i]);
} }
opt.changes = length(uset) - lpre;
return uset; return uset;
} }

View file

@ -385,7 +385,11 @@ async function sliceZ(z, points, options = {}) {
let groups = groupFn(lines, z, options); let groups = groupFn(lines, z, options);
if (options.union) { if (options.union) {
// simplistic healing of non-manifold meshes // simplistic healing of non-manifold meshes
groups = POLY.flatten(POLY.union(POLY.nest(groups), 0.1, true), null, true); let opt = { x: 1 };
let union = POLY.union(POLY.nest(groups), 0.1, true, opt);
// track total poly length changes to determine if healed
rval.changes = opt.changes;
groups = POLY.flatten(union, null, true);
} }
rval.groups = groups; rval.groups = groups;
} }

View file

@ -159,6 +159,7 @@ FDM.slice = function(settings, widget, onupdate, ondone) {
let points = widget.getPoints(); let points = widget.getPoints();
let indices = []; let indices = [];
let heights = []; let heights = [];
let healed = false;
// handle z cutting (floor method) and base flattening // handle z cutting (floor method) and base flattening
let zPress = isBelt ? process.firstLayerFlatten || 0 : 0; let zPress = isBelt ? process.firstLayerFlatten || 0 : 0;
@ -296,12 +297,16 @@ FDM.slice = function(settings, widget, onupdate, ondone) {
}).then((output) => { }).then((output) => {
// post process slices and re-incorporate missing meta-data // post process slices and re-incorporate missing meta-data
return output.slices.map(data => { return output.slices.map(data => {
let { z, clip, lines, groups } = data; let { z, clip, lines, groups, changes } = data;
if (!data.tops) return null; if (!data.tops) return null;
let slice = newSlice(z).addTops(data.tops); let slice = newSlice(z).addTops(data.tops);
slice.index = indices.indexOf(z); slice.index = indices.indexOf(z);
slice.height = heights[slice.index]; slice.height = heights[slice.index];
slice.clips = clip; slice.clips = clip;
if (changes) {
healed = true;
slice.changes = changes;
}
if (process.xray) { if (process.xray) {
slice.index = process.xrayi.shift(); slice.index = process.xrayi.shift();
slice.lines = lines; slice.lines = lines;
@ -342,6 +347,11 @@ FDM.slice = function(settings, widget, onupdate, ondone) {
} }
async function onSliceDone(slices) { async function onSliceDone(slices) {
// alert non-manifold parts
if (healed) {
onupdate(null, null, "part may not be manifold");
}
// remove all empty slices above part but leave below // remove all empty slices above part but leave below
// for multi-part (multi-extruder) setups where the void is ok // for multi-part (multi-extruder) setups where the void is ok
// also reverse because slicing occurs bottom-up // also reverse because slicing occurs bottom-up

View file

@ -433,11 +433,13 @@ kiri.worker = {
send.data({send_end: time()}); send.data({send_end: time()});
} }
send.done({done: true}); send.done({done: true});
}, function(update, msg) { }, function(update, msg, alert) {
now = time(); now = time();
if (now - last < 10 && update < 0.99) return; // on alert
if (alert) send.data({ alert });
// on update // on update
send.data({update: (0.05 + update * 0.95), updateStatus: msg}); if (now - last < 10 && update < 0.99) return;
if (update || msg) send.data({update: (0.05 + update * 0.95), updateStatus: msg});
last = now; last = now;
}); });
}, },

View file

@ -161,7 +161,10 @@ function prepareSlices(callback, scale = 1, offset = 0) {
// start next widget slice // start next widget slice
sliceNext(); sliceNext();
} }
}, (update, msg) => { }, (update, msg, alert) => {
if (alert) {
api.show.alert(alert);
}
if (msg && msg !== lastMsg) { if (msg && msg !== lastMsg) {
let mark = Date.now(); let mark = Date.now();
if (lastMsg) { if (lastMsg) {
@ -171,12 +174,14 @@ function prepareSlices(callback, scale = 1, offset = 0) {
startTime = mark; startTime = mark;
} }
// on update // on update
track[widget.id] = (update || 0) * factor; if (update >= 0) {
totalProgress = 0; track[widget.id] = (update || 0) * factor;
for (let w of slicing) { totalProgress = 0;
totalProgress += (track[w.id] || 0); for (let w of slicing) {
totalProgress += (track[w.id] || 0);
}
show.progress(offset + (totalProgress / widgets.length) * scale, msg);
} }
show.progress(offset + (totalProgress / widgets.length) * scale, msg);
}); });
} }

View file

@ -733,6 +733,9 @@ class Widget {
// executed from kiri.js // executed from kiri.js
kiri.client.slice(settings, this, function(reply) { kiri.client.slice(settings, this, function(reply) {
if (reply.alert) {
onupdate(null, null, reply.alert);
}
if (reply.update) { if (reply.update) {
onupdate(reply.update, reply.updateStatus); onupdate(reply.update, reply.updateStatus);
} }
@ -774,8 +777,8 @@ class Widget {
ondone(); ondone();
}; };
let catchupdate = function(progress, message) { let catchupdate = function(progress, message, alert) {
onupdate(progress, message); onupdate(progress, message, alert);
}; };
let drv = driver[settings.mode.toUpperCase()]; let drv = driver[settings.mode.toUpperCase()];