checkpoint new support / rotation work

This commit is contained in:
Stewart Allen 2021-01-24 00:13:09 -05:00
commit dba922753c
9 changed files with 250 additions and 158 deletions

View file

@ -51,8 +51,9 @@
# FDM - BELT
* `B` layer retract broken
* `B` finish supports for belt printing. clip below belt. add progress.
* `B` layer retract broken?
* `B` infill / thin-fill is generating tons of small linear segments
* `B` finish supports for belt printing. add progress.
# CAM

View file

@ -70,7 +70,10 @@
// return cached or refreshed (when update = true) bounding box
GP.getBoundingBox = function(update) {
if (update || !this.boundingBox) this.computeBoundingBox();
if (update || !this.boundingBox) {
this.boundingBox = null;
this.computeBoundingBox();
}
this.boundingBox.dim = this.boundingBox.max.clone().sub(this.boundingBox.min);
return this.boundingBox;
};

View file

@ -123,17 +123,18 @@ KIRI.work = {
},
// widget sync
sync: function(widget) {
let widgets = widget ? [ widget ] : KIRI.api.widgets.all();
sync: function() {
let widgets = KIRI.api.widgets.all();
widgets.forEach(widget => {
if (widget.modified || !syncd[widget.id]) {
syncd[widget.id] = true;
let vertices = widget.getGeoVertices().buffer.slice(0);
send("sync", {
id: widget.id,
group: widget.group.id,
track: widget.track,
vertices: vertices,
position: widget.mesh.position,
tracking: widget.track
}, done => {
widget.modified = false;
}, [vertices]);
@ -141,8 +142,31 @@ KIRI.work = {
});
},
rotate: function(settings, callback) {
send("rotate", { settings }, reply => {
if (reply.group) {
for (let widget of KIRI.Widget.Groups.forid(reply.group)) {
widget.belt = reply.belt;
}
} else if (callback) {
callback();
}
});
},
unrotate: function(settings, callback) {
send("unrotate", { settings }, reply => {
if (reply.group) {
for (let widget of KIRI.Widget.Groups.forid(reply.group)) {
widget.rotinfo = reply.rotinfo;
}
} else if (callback) {
callback();
}
});
},
slice: function(settings, widget, callback) {
CLIENT.sync(widget);
slicing[widget.id] = callback;
send("slice", {

View file

@ -355,7 +355,9 @@
return map;
},
new: newWidget,
all: function() { return WIDGETS.slice() },
all: () => { return WIDGETS.slice() },
add: (widget) => { WIDGETS.push(widget) },
filter: (fn) => { WIDGETS = WIDGETS.filter(fn) },
for: forAllWidgets,
load: Widget.loadFromCatalog,
meshes: meshArray,
@ -858,6 +860,9 @@
setOpacity(color.slicing_opacity);
STACKS.clear();
KIRI.client.clear();
KIRI.client.sync();
KIRI.client.rotate(settings);
// for each widget, slice
forAllWidgets(function(widget) {
@ -867,11 +872,12 @@
startTime = Date.now(),
lastMsg,
camOrLaser = mode === 'CAM' || mode === 'LASER',
stack = STACKS.create(widget.id, widget.mesh);
stack = widget.stack = STACKS.create(widget.id, widget.mesh);
widget.stats.progress = 0;
widget.setColor(color.slicing);
widget.slice(settings, function(sliced, error) {
widget.rotinfo = null;
let mark = Date.now();
// update UI info
if (sliced) {
@ -881,22 +887,26 @@
}
API.event.emit('slice', getMode());
}
// on done
segtimes[`${segNumber}_draw`] = widget.render(stack);
// rotate stack for belt beds
if (settings.device.bedBelt && widget.rotinfo) {
stack.obj.rotate(widget.rotinfo);
}
updateSliderMax(true);
setVisibleLayer(-1, 0);
if (scale === 1) {
// clear wireframe
widget.setWireframe(false, color.wireframe, color.wireframe_opacity);
widget.setOpacity(camOrLaser ? color.cam_sliced_opacity : color.sliced_opacity);
widget.setColor(color.deselected);
}
// on the last exit, update ui and call the callback
if (--countdown === 0 || error || errored) {
KIRI.client.unrotate(settings, () => {
forAllWidgets(widget => {
// on done
segtimes[`${segNumber}_draw`] = widget.render(stack);
// rotate stack for belt beds
if (widget.rotinfo) {
widget.stack.obj.rotate(widget.rotinfo);
}
if (scale === 1) {
// clear wireframe
widget.setWireframe(false, color.wireframe, color.wireframe_opacity);
widget.setOpacity(camOrLaser ? color.cam_sliced_opacity : color.sliced_opacity);
widget.setColor(color.deselected);
}
});
updateSliderMax(true);
setVisibleLayer(-1, 0);
});
// mark slicing complete for prep/preview
complete.slice = true;
if (scale === 1) {
@ -2077,6 +2087,7 @@
let newWidgets = [],
oldWidgets = js2o(SDB.getItem('ws-widgets'), []);
forAllWidgets(function(widget) {
if (widget.synth) return;
newWidgets.push(widget.id);
oldWidgets.remove(widget.id);
widget.saveState();

View file

@ -32,6 +32,10 @@
let Group = Widget.Groups = {
list: () => {
return groups.slice()
},
forid: function(id) {
for (let i=0; i<groups.length; i++) {
if (groups[i].id === id) return groups[i];
@ -101,7 +105,7 @@
* @params {String} [id]
* @constructor
*/
function Widget(id,group) {
function Widget(id, group) {
this.id = id || new Date().getTime().toString(36)+(nextId++);
this.group = group || [];
this.group.push(this);
@ -461,11 +465,11 @@
this.modified = true;
};
PRO.rotate = function(x, y, z) {
PRO.rotate = function(x, y, z, temp) {
this.group.forEach(w => {
w._rotate(x, y, z, false);
w._rotate(x, y, z, temp);
});
this.center();
this.center(false);
};
PRO._rotate = function(x, y, z, temp) {

View file

@ -10,7 +10,8 @@ let BASE = self.base,
print: null,
snap: null
},
cache = {};
wgroup = {},
wcache = {};
// catch clipper alerts and convert to console messages
self.alert = function(o) {
@ -24,7 +25,9 @@ BASE.debug.disable();
const dispatch =
KIRI.server =
KIRI.worker = {
cache: cache,
group: wgroup,
cache: wcache,
decimate: function(data, send) {
let { vertices, options } = data;
@ -38,135 +41,152 @@ KIRI.worker = {
send.done();
},
clear: function(data, send) {
current.snap = null;
current.print = null;
if (!data.id) {
dispatch.group = wgroup = {};
dispatch.cache = wcache = {};
send.done({ clear: true });
return;
}
let had = wcache[data.id] !== undefined;
delete wcache[data.id];
send.done({
id: data.id,
had: had,
has: wcache[data.id] !== undefined
});
},
// widget sync
sync: function(data, send) {
let group = wgroup[data.group];
if (!group) {
group = [];
group.id = data.group;
wgroup[data.group] = group;
}
let vertices = new Float32Array(data.vertices),
points = BASE.verticesToPoints(vertices, { maxpass: 0 }),
widget = KIRI.newWidget(data.id).setPoints(points);
widget = KIRI.newWidget(data.id, group).loadVertices(vertices);
// do it here so cancel can work
cache[data.id] = widget;
wcache[data.id] = widget;
// stored for possible future rotations
widget.vertices = vertices;
// fake mesh object to satisfy printing
widget.track = data.tracking;
widget.mesh = {
widget: widget,
position: data.position
};
// restore tracking object
widget.track = data.track;
send.done(data.id);
},
slice: function(data, send) {
let { id, settings } = data;
rotate: function(data, send) {
let { settings } = data;
if (!settings.device.bedBelt) {
return send.done({});
}
send.data({update:0.05, updateStatus:"slicing"});
let widget = cache[data.id],
last = time(),
xpos,
ypos,
now;
try {
let rotation = (Math.PI/180) * (settings.device.bedBelt ? 45 : 0);
if (rotation) {
// need min y for post-rotation offset in prepare
let vert = widget.vertices;
let miny = Infinity;
function mins(vert) {
let miny = Infinity, minz = Infinity;
for (let i=0, l=vert.length; i<l; ) {
let x = vert[i++];
let y = vert[i++];
let z = vert[i++];
if (z < 0.01) miny = Math.min(miny, y);
miny = Math.min(miny, y);
minz = Math.min(minz, z);
}
let bb1 = widget.getBoundingBox(true);
let track = widget.track;
xpos = track.pos.x;
ypos = settings.device.bedDepth / 2 + track.pos.y + miny;
widget.mesh = null;
widget.points = null;
// this super ugly hack injects fake support faces
// into the widget mesh so they can be rotated and extracted
let fv = Array.from(widget.vertices);
let fvl = fv.length;
let fixed = Object.values(settings.widget[widget.id].support || {});
for (let col of fixed) {
fv.push(col.x);
fv.push(col.y);
fv.push(col.z);
fv.push(col.x);
fv.push(col.y);
fv.push(col.z);
fv.push(col.x);
fv.push(col.y);
fv.push(col.z);
}
let f2l = fv.length;
let f32 = fv.toFloat32();
// use falsified vertices
widget.loadVertices(f32);
// widget.loadVertices(widget.vertices);
widget._rotate(rotation,0,0,true);
widget.center(false, true);
let bb2 = widget.getBoundingBox(true);
// hack part 2: recover rotated support column mid-points
for (let i=0; i<fixed.length; i++) {
let x = f32[fvl + i*9 + 0];
let y = f32[fvl + i*9 + 1];
let z = f32[fvl + i*9 + 2];
fixed[i].y = y;
fixed[i].z = z;
}
widget.belt = { xpos, ypos };
return {miny, minz};
}
widget.slice(settings, function(error) {
if (error) {
send.data({error: error});
} else {
const slices = widget.slices || [];
send.data({send_start: time()});
send.data({
stats: widget.stats,
slices: slices.length,
});
slices.forEach(function(slice,index) {
const state = { zeros: [] };
send.data({index: index, slice: slice.encode(state)}, state.zeros);
})
send.data({send_end: time()});
// unrotate and send delta coordinates
if (rotation) {
widget.setPoints(null);
widget._rotate(-rotation,0,0,true);
let wbb = widget.getBoundingBox(true);
widget.center(false, true);
let dy = (wbb.max.y + wbb.min.y)/2;
let dz = wbb.min.z;
widget.rotinfo = { angle: 45, dy, dz, xpos, ypos };
send.data({ rotinfo: widget.rotinfo });
}
for (let group of Object.values(wgroup)) {
let widget = group[0];
let rotation = (Math.PI / 180) * 45;
// need min y for post-rotation offset in prepare
// let vert = widget.vertices;
// let miny = Infinity;
// for (let i=0, l=vert.length; i<l; ) {
// let x = vert[i++];
// let y = vert[i++];
// let z = vert[i++];
// if (z < 0.01) miny = Math.min(miny, y);
// }
let min1 = mins(widget.vertices);
let miny = min1.miny;
widget.groupBounds();
let track = widget.track;
let xpos = track.pos.x;
let ypos = settings.device.bedDepth / 2 + track.pos.y + miny;
widget.rotate(rotation,0,0,true);
widget.groupBounds();
widget.belt = { xpos, ypos };
for (let others of group.slice(1)) {
others.belt = widget.belt;
}
send.done({done: true});
}, function(update, msg) {
now = time();
if (now - last < 10 && update < 0.99) return;
// on update
send.data({update: (0.05 + update * 0.95), updateStatus: msg});
last = now;
});
send.data({group: group.id, belt: widget.belt});
}
send.done({});
},
unrotate: function(data, send) {
let { settings } = data;
if (!settings.device.bedBelt) {
return send.done({});
}
let rotation = (Math.PI / 180) * 45;
for (let group of Object.values(wgroup)) {
let widget = group[0];
widget.groupBounds();
widget.rotate(-rotation,0,0,true);
let { dy, dz } = widget.track.center;
widget.groupBounds();
let { xpos, ypos } = widget.belt;
widget.rotinfo = { angle: 45, dy, dz, xpos, ypos };
for (let others of group.slice(1)) {
others.rotinfo = widget.rotinfo;
}
send.data({group: group.id, rotinfo: widget.rotinfo});
}
send.done({});
},
slice: function(data, send) {
send.data({update:0.001, updateStatus:"slicing"});
let settings = data.settings,
widget = wcache[data.id],
last = time(),
now;
try {
widget.slice(settings, function(error) {
if (error) {
send.data({error: error});
} else {
const slices = widget.slices || [];
send.data({send_start: time()});
send.data({
stats: widget.stats,
slices: slices.length,
});
slices.forEach(function(slice,index) {
const state = { zeros: [] };
send.data({index: index, slice: slice.encode(state)}, state.zeros);
})
send.data({send_end: time()});
}
send.done({done: true});
}, function(update, msg) {
now = time();
if (now - last < 10 && update < 0.99) return;
// on update
send.data({update: (0.05 + update * 0.95), updateStatus: msg});
last = now;
});
} catch (error) {
send.data({error: error.toString()});
console.log(error);
@ -175,7 +195,7 @@ KIRI.worker = {
prepare: function(data, send) {
// create widget array from id:widget cache
const widgets = Object.values(cache);
const widgets = Object.values(wcache);
// let client know we've started
send.data({update:0.05, updateStatus:"preview"});
@ -254,7 +274,7 @@ KIRI.worker = {
z: origin.z
};
const device = settings.device;
const print = current.print = KIRI.newPrint(settings, Object.values(cache));
const print = current.print = KIRI.newPrint(settings, Object.values(wcache));
const tools = device.extruders;
const mode = settings.mode;
const thin = settings.controller.lineType === 'line' || mode !== 'FDM';
@ -280,30 +300,13 @@ KIRI.worker = {
out.point = BASE.newPoint(x,y,z || 0);
});
});
const print = current.print = KIRI.newPrint(null, Object.values(cache));
const print = current.print = KIRI.newPrint(null, Object.values(wcache));
const layers = KIRI.driver.FDM.prepareRender(parsed, progress => {
send.data({ progress });
}, { thin: true });
send.done({parsed: KIRI.codec.encode(layers)});
},
clear: function(data, send) {
current.snap = null;
current.print = null;
if (!data.id) {
cache = {};
send.done({ clear: true });
return;
}
let had = cache[data.id] !== undefined;
delete cache[data.id];
send.done({
id: data.id,
had: had,
has: cache[data.id] !== undefined
});
},
config: function(data, send) {
const update = {};
if (data.base) {

View file

@ -20,6 +20,18 @@
FDM.init = function(kiri, api) {
API = api;
SPACE = api.const.SPACE;
function filterSynth() {
// remove synth widgets
api.widgets.filter((widget) => {
if (widget.track.synth) {
api.const.SPACE.platform.remove(widget.mesh);
kiri.Widget.Groups.remove(widget);
}
return !widget.track.synth
});
}
api.event.on("mode.set", mode => {
isFdmMode = mode === 'FDM';
lastMode = mode;
@ -28,6 +40,7 @@
api.event.on("view.set", view => {
lastView = view;
updateVisiblity();
filterSynth();
});
api.event.on("settings.load", (settings) => {
if (settings.mode !== 'FDM') return;
@ -98,6 +111,37 @@
}
func.sdone();
updateVisiblity();
// synth support widget for each widget group
let synth = [];
for (let group of kiri.Widget.Groups.list()) {
let count = 0;
let merged = new THREE.Geometry();
for (let widget of group) {
if (widget.sups) {
for (let sup of Object.values(widget.sups)) {
merged.merge(sup.box.geometry, sup.box.matrix);
count++;
}
}
}
if (!count) {
continue;
}
let bbg = new THREE.BufferGeometry().fromGeometry(merged);
let sw = kiri.newWidget(null, group);
let fwp = group[0].track.pos;
sw.loadGeometry(bbg);
sw._move(fwp.x, fwp.y, fwp.z);
api.widgets.add(sw);
sw.track.synth = true;
api.const.SPACE.platform.add(sw.mesh);
}
});
api.event.on("slice.end", () => {
if (!isFdmMode) {
return;
}
});
api.event.on("key.esc", () => {
if (!isFdmMode) {

View file

@ -89,7 +89,7 @@
// nest and offset tops
POLY.nest(tops).forEach(function(poly) {
poly.offset(-offset + nozzle / 2).forEach(function(brim) {
brim.move(widget.mesh.position);
brim.move(widget.track.pos);
brims.push(brim);
});
});
@ -290,7 +290,8 @@
// establish offsets
for (let widget of widgets) {
let { rotinfo, belt } = widget;
let offset = widget.mesh ? Object.clone(widget.mesh.position) : {x:0, y:0, z:0};
let offset = Object.clone(widget.track.pos);
// let offset = widget.mesh ? Object.clone(widget.mesh.position) : {x:0, y:0, z:0};
if (isBelt) {
offset.x = rotinfo.xpos;
offset.y = -belt.midy;

View file

@ -199,8 +199,9 @@
});
// fixed supports (generated ahead of time)
const fixed = Object.values(settings.widget[widget.id].support || {});
let shadow = null;
let wannot = settings.widget[widget.id] || {},
fixed = Object.values(wannot.support || {}),
shadow = null;
if (fixed.length || spro.sliceSupportEnable) {
// create shadow. TODO test if any supports set
let alltops = slices.map(slice => slice.topPolys()).flat();
@ -284,7 +285,7 @@
doSupportFill(slice, lineWidth, spro.sliceSupportDensity, minArea);
}, "support");
} else if (true) {
doSupportBelt(slices, spro, fixed, shadow, doupdate);
// doSupportBelt(slices, spro, fixed, shadow, doupdate);
}
// render if not explicitly disabled