add concurrent slicing, new threaded preference checkbox
This commit is contained in:
parent
a4d6c00a8d
commit
8e6a1e5747
9 changed files with 283 additions and 179 deletions
1
app.js
1
app.js
|
|
@ -345,6 +345,7 @@ const script = {
|
|||
"mode/fdm/driver",
|
||||
"mode/fdm/slice",
|
||||
"kiri/slice",
|
||||
"kiri/slicer",
|
||||
"kiri/layers",
|
||||
"kiri/widget",
|
||||
"kiri/codec",
|
||||
|
|
|
|||
|
|
@ -676,9 +676,10 @@
|
|||
exportLocal: false,
|
||||
exportPreview: false,
|
||||
decimate: true,
|
||||
detail: "good",
|
||||
detail: "100",
|
||||
animesh: "200",
|
||||
healMesh: false,
|
||||
threaded: false,
|
||||
ortho: false,
|
||||
devel: false
|
||||
},
|
||||
|
|
|
|||
|
|
@ -115,10 +115,10 @@
|
|||
level = level.value;
|
||||
let rez = BASE.config.clipperClean;
|
||||
switch (level) {
|
||||
case 'best': rez = 50; break;
|
||||
case 'good': rez = BASE.config.clipperClean; break;
|
||||
case 'fair': rez = 500; break;
|
||||
case 'poor': rez = 1000; break;
|
||||
case '100': rez = 50; break;
|
||||
case '75': rez = BASE.config.clipperClean; break;
|
||||
case '50': rez = 500; break;
|
||||
case '20': rez = 1000; break;
|
||||
}
|
||||
KIRI.client.config({
|
||||
base: { clipperClean: rez }
|
||||
|
|
@ -157,6 +157,7 @@
|
|||
control.exportPreview = UI.exportPreview.checked;
|
||||
control.decimate = UI.decimate.checked;
|
||||
control.healMesh = UI.healMesh.checked;
|
||||
control.threaded = UI.threaded.checked;
|
||||
control.ortho = UI.ortho.checked;
|
||||
control.devel = UI.devel.checked;
|
||||
SPACE.view.setZoom(control.reverseZoom, control.zoomSpeed);
|
||||
|
|
@ -1642,6 +1643,7 @@
|
|||
detail: UC.newSelect(LANG.pt_qual_s, {title: LANG.pt_qual_l, action: detailSave}, "detail"),
|
||||
decimate: UC.newBoolean(LANG.pt_deci_s, booleanSave, {title: LANG.pt_deci_l}),
|
||||
healMesh: UC.newBoolean(LANG.pt_heal_s, booleanSave, {title: LANG.pt_heal_l}),
|
||||
threaded: UC.newBoolean(LANG.pt_thrd_s, booleanSave, {title: LANG.pt_thrd_l}),
|
||||
|
||||
prefadd: UC.checkpoint($('prefs-add')),
|
||||
|
||||
|
|
@ -2432,6 +2434,7 @@
|
|||
UI.autoSave.checked = control.autoSave;
|
||||
UI.decimate.checked = control.decimate;
|
||||
UI.healMesh.checked = control.healMesh;
|
||||
UI.threaded.checked = control.threaded;
|
||||
UI.ortho.checked = control.ortho;
|
||||
UI.devel.checked = control.devel;
|
||||
lineTypeSave();
|
||||
|
|
|
|||
|
|
@ -165,10 +165,10 @@
|
|||
{ name: "8", id: 8 }
|
||||
],
|
||||
detail: [
|
||||
{ name: "best" },
|
||||
{ name: "good" },
|
||||
{ name: "fair" },
|
||||
{ name: "poor" },
|
||||
{ name: "100" },
|
||||
{ name: "75" },
|
||||
{ name: "50" },
|
||||
{ name: "25" },
|
||||
],
|
||||
linetype: [
|
||||
{ name: "path" },
|
||||
|
|
|
|||
|
|
@ -77,6 +77,22 @@ const funcs = {
|
|||
reply({ clips });
|
||||
},
|
||||
|
||||
sliceBucket: data => {
|
||||
let { points, slices, options } = data;
|
||||
let i = 0, p = 0, realp = new Array(points.length / 3);
|
||||
while (i < points.length) {
|
||||
realp[p++] = BASE.newPoint(points[i++], points[i++], points[i++]);
|
||||
}
|
||||
let output = [];
|
||||
for (let slice of slices) {
|
||||
output.push({
|
||||
slice,
|
||||
tops: KIRI.slicer.sliceZ(slice.z, realp, options).tops
|
||||
});
|
||||
}
|
||||
reply({ output: CODEC.encode(output) });
|
||||
},
|
||||
|
||||
bad: data => {
|
||||
reply({error: "invalid command"});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,9 +7,10 @@
|
|||
if (self.kiri.slicer) return;
|
||||
|
||||
self.kiri.slicer = {
|
||||
slice: slice,
|
||||
sliceWidget: sliceWidget,
|
||||
connectLines: connectLines
|
||||
slice,
|
||||
sliceZ,
|
||||
sliceWidget,
|
||||
connectLines
|
||||
};
|
||||
|
||||
let KIRI = self.kiri,
|
||||
|
|
@ -67,11 +68,11 @@
|
|||
zLines = {}, // map count of z index lines
|
||||
zScale, // bucket span in z units
|
||||
timeStart = time(),
|
||||
slices = [],
|
||||
zSum = 0.0,
|
||||
buckets = [],
|
||||
i, j = 0, k, p1, p2, p3, px,
|
||||
CPRO = KIRI.driver.CAM.process;
|
||||
CPRO = KIRI.driver.CAM.process,
|
||||
concurrent = options.concurrent ? KIRI.minions.concurrent : 0;
|
||||
|
||||
if (options.add) {
|
||||
zMax += zInc;
|
||||
|
|
@ -133,12 +134,20 @@
|
|||
*/
|
||||
let bucketCount = Math.max(1, Math.ceil(zMax / (zSum / points.length)) - 1);
|
||||
|
||||
if (concurrent > 1) {
|
||||
if (bucketCount < concurrent) {
|
||||
bucketCount = concurrent;
|
||||
} else if (bucketCount > 128) {
|
||||
bucketCount = 128;
|
||||
}
|
||||
}
|
||||
|
||||
zScale = 1 / (zMax / bucketCount);
|
||||
|
||||
if (bucketCount > 1) {
|
||||
// create empty buckets
|
||||
for (i = 0; i < bucketCount + 1; i++) {
|
||||
buckets.push({ points: []});
|
||||
buckets.push({ points: [], slices: [] });
|
||||
}
|
||||
|
||||
// copy triples into all matching z-buckets
|
||||
|
|
@ -158,7 +167,7 @@
|
|||
}
|
||||
}
|
||||
} else {
|
||||
buckets.push({ points });
|
||||
buckets.push({ points, slices: [] });
|
||||
}
|
||||
|
||||
// we need Z ordered list for laser auto or adaptive fdm slicing
|
||||
|
|
@ -259,7 +268,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
// create a Slice for each z offset in the zIndexes array
|
||||
// create buckets data structure
|
||||
for (let i = 0; i < zIndexes.length; i++) {
|
||||
let ik = zIndexes[i].toFixed(5),
|
||||
onFlat = false,
|
||||
|
|
@ -270,184 +279,222 @@
|
|||
if (!useFlats && (onFlat || onLine)) {
|
||||
zIndexes[i] -= -0.001;
|
||||
}
|
||||
// slice next layer and add to slices[] array
|
||||
sliceZ(zIndexes[i], zHeights[i], onFlat, onLine, zThick[i]);
|
||||
bucketZ(i, zIndexes[i], zHeights[i], onFlat, onLine, zThick[i]);
|
||||
onupdate(i / zIndexes.length);
|
||||
}
|
||||
|
||||
// connect slices into linked list for island/bridge projections
|
||||
for (i=1; i<slices.length; i++) {
|
||||
slices[i-1].up = slices[i];
|
||||
slices[i].down = slices[i-1];
|
||||
}
|
||||
// create slices from each bucketed region
|
||||
sliceBuckets().then(slices => {
|
||||
slices = slices.sort((a,b) => a.index - b.index);
|
||||
|
||||
slices.slice_time = time() - timeStart;
|
||||
|
||||
// pass Slices array back to ondone function
|
||||
ondone(slices);
|
||||
|
||||
/** ***** SLICING FUNCTIONS ***** */
|
||||
|
||||
/**
|
||||
* given a point, append to the correct
|
||||
* 'where' objec tarray (on, over or under)
|
||||
*
|
||||
* @param {Point} p
|
||||
* @param {number} z offset
|
||||
* @param {Obejct} where
|
||||
*/
|
||||
function checkUnderOverOn(p, z, where) {
|
||||
let delta = p.z - z;
|
||||
if (Math.abs(delta) < CONF.precision_slice_z) { // on
|
||||
where.on.push(p);
|
||||
} else if (delta < 0) { // under
|
||||
where.under.push(p);
|
||||
} else { // over
|
||||
where.over.push(p);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a point over and under a z offset, calculate
|
||||
* and return the intersection point on that z plane
|
||||
*
|
||||
* @param {Point} over
|
||||
* @param {Point} under
|
||||
* @param {number} z offset
|
||||
* @returns {Point} intersection point
|
||||
*/
|
||||
function intersectPoints(over, under, z) {
|
||||
let ip = [];
|
||||
for (let i = 0; i < over.length; i++) {
|
||||
for (let j = 0; j < under.length; j++) {
|
||||
ip.push(over[i].intersectZ(under[j], z));
|
||||
}
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure points are unique with a cache/key algorithm
|
||||
*/
|
||||
function getCachedPoint(phash, p) {
|
||||
let cached = phash[p.key];
|
||||
if (!cached) {
|
||||
phash[p.key] = p;
|
||||
return p;
|
||||
}
|
||||
return cached;
|
||||
}
|
||||
/**
|
||||
* Given two points and hints about their edges,
|
||||
* return a new Line object with points sorted
|
||||
* lexicographically by key. This allows for future
|
||||
* line de-duplication and joins.
|
||||
*
|
||||
* @param {Object} phash
|
||||
* @param {Point} p1
|
||||
* @param {Point} p2
|
||||
* @param {boolean} [coplanar]
|
||||
* @param {boolean} [edge]
|
||||
* @returns {Line}
|
||||
*/
|
||||
function makeZLine(phash, p1, p2, coplanar, edge) {
|
||||
p1 = getCachedPoint(phash, p1);
|
||||
p2 = getCachedPoint(phash, p2);
|
||||
let line = newOrderedLine(p1,p2);
|
||||
line.coplanar = coplanar || false;
|
||||
line.edge = edge || false;
|
||||
return line;
|
||||
}
|
||||
|
||||
/**
|
||||
* process a single z-slice on a single mesh and
|
||||
* add to slices array
|
||||
*
|
||||
* @param {number} z
|
||||
* @param {number} [height] optional real height (fdm)
|
||||
*/
|
||||
function sliceZ(z, height, onflat, online, thick) {
|
||||
let phash = {},
|
||||
lines = [],
|
||||
slice = newSlice(z),
|
||||
points = buckets[Math.floor(z * zScale)].points;
|
||||
|
||||
// iterate over matching buckets for this z offset
|
||||
for (let i = 0; i < points.length; ) {
|
||||
p1 = points[i++];
|
||||
p2 = points[i++];
|
||||
p3 = points[i++];
|
||||
let where = {under: [], over: [], on: []};
|
||||
checkUnderOverOn(p1, z, where);
|
||||
checkUnderOverOn(p2, z, where);
|
||||
checkUnderOverOn(p3, z, where);
|
||||
if (where.under.length === 3 || where.over.length === 3) {
|
||||
// does not intersect (all 3 above or below)
|
||||
} else if (where.on.length === 2) {
|
||||
// one side of triangle is on the Z plane and 3rd is below
|
||||
// drop lines with 3rd above because that leads to ambiguities
|
||||
// with complex nested polygons on flat surface
|
||||
if (where.under.length === 1) {
|
||||
lines.push(makeZLine(phash, where.on[0], where.on[1], false, true));
|
||||
}
|
||||
} else if (where.on.length === 3) {
|
||||
// triangle is coplanar with Z
|
||||
// we drop these because this face is attached to 3 others
|
||||
// that will satisfy the if above (line) with 2 points
|
||||
} else if (where.under.length === 0 || where.over.length === 0) {
|
||||
// does not intersect but one point is on the slice Z plane
|
||||
} else {
|
||||
// compute two point intersections and construct line
|
||||
let line = intersectPoints(where.over, where.under, z);
|
||||
if (line.length < 2 && where.on.length === 1) {
|
||||
line.push(where.on[0]);
|
||||
}
|
||||
if (line.length === 2) {
|
||||
lines.push(makeZLine(phash, line[0], line[1]));
|
||||
} else {
|
||||
console.log({msg: "invalid ips", line: line, where: where});
|
||||
}
|
||||
}
|
||||
// connect slices into linked list for island/bridge projections
|
||||
for (i=1; i<slices.length; i++) {
|
||||
slices[i-1].up = slices[i];
|
||||
slices[i].down = slices[i-1];
|
||||
}
|
||||
|
||||
// allow empty slices in CAM swap mode (for topos w/ gaps)
|
||||
// if (lines.length == 0 && !(options.swapX || options.swapY)) return;
|
||||
if (lines.length == 0 && options.noEmpty) return;
|
||||
slices.slice_time = time() - timeStart;
|
||||
|
||||
slice.height = height;
|
||||
slice.index = slices.length;
|
||||
slice.thick = thick;
|
||||
// pass Slices array back to ondone function
|
||||
ondone(slices);
|
||||
});
|
||||
|
||||
// de-dup and group lines
|
||||
lines = removeDuplicateLines(lines);
|
||||
let groups = connectLines(lines, slice.z);
|
||||
|
||||
// simplistic healing of bad meshes
|
||||
if (options.union) {
|
||||
groups = POLY.flatten(POLY.union(POLY.nest(groups), null, true), null, true);
|
||||
}
|
||||
|
||||
if ((debug && lines.excessive) || xray) {
|
||||
const dash = xray || 3;
|
||||
lines.forEach((line, i) => {
|
||||
const group = i % dash;
|
||||
const color = [ 0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff ][group];
|
||||
slice.output().setLayer(`xl-${group}`, color).addLine(line.p1, line.p2);
|
||||
});
|
||||
}
|
||||
|
||||
// identify and add tops to slice
|
||||
POLY.nest(groups).forEach((poly, i) => {
|
||||
slice.addTop(poly);
|
||||
if (xray) {
|
||||
const group = i % (xray || 3);
|
||||
const color = [ 0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff ][group];
|
||||
slice.output().setLayer(`xg-${group}`, color).addPoly(poly);
|
||||
}
|
||||
function bucketZ(index, z, height, thick) {
|
||||
let bucket = buckets[Math.floor(z * zScale)];
|
||||
bucket.slices.push({
|
||||
index, z, height, thick
|
||||
});
|
||||
|
||||
slices.push(slice);
|
||||
}
|
||||
|
||||
async function sliceBuckets() {
|
||||
let output = [];
|
||||
// console.log({buckets});
|
||||
if (concurrent < 2) {
|
||||
sliceBucketsLocal(buckets, output);
|
||||
} else {
|
||||
let promises = [];
|
||||
for (let bucket of buckets) {
|
||||
promises.push(KIRI.minions.sliceBucket(bucket, options, output));
|
||||
}
|
||||
await Promise.all(promises);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
function sliceBucketsLocal(buckets, output) {
|
||||
for (let bucket of buckets) {
|
||||
for (let slice of bucket.slices) {
|
||||
let { index, z, height, thick } = slice;
|
||||
let { lines, groups, tops } = sliceZ(z, bucket.points, options);
|
||||
slice = newSlice(z).addTops(tops);
|
||||
slice.height = height;
|
||||
slice.index = index;
|
||||
slice.thick = thick;
|
||||
output.push(slice);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** ***** SLICING FUNCTIONS ***** */
|
||||
|
||||
/**
|
||||
* given a point, append to the correct
|
||||
* 'where' objec tarray (on, over or under)
|
||||
*
|
||||
* @param {Point} p
|
||||
* @param {number} z offset
|
||||
* @param {Obejct} where
|
||||
*/
|
||||
function checkUnderOverOn(p, z, where) {
|
||||
let delta = p.z - z;
|
||||
if (Math.abs(delta) < CONF.precision_slice_z) { // on
|
||||
where.on.push(p);
|
||||
} else if (delta < 0) { // under
|
||||
where.under.push(p);
|
||||
} else { // over
|
||||
where.over.push(p);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a point over and under a z offset, calculate
|
||||
* and return the intersection point on that z plane
|
||||
*
|
||||
* @param {Point} over
|
||||
* @param {Point} under
|
||||
* @param {number} z offset
|
||||
* @returns {Point} intersection point
|
||||
*/
|
||||
function intersectPoints(over, under, z) {
|
||||
let ip = [];
|
||||
for (let i = 0; i < over.length; i++) {
|
||||
for (let j = 0; j < under.length; j++) {
|
||||
ip.push(over[i].intersectZ(under[j], z));
|
||||
}
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure points are unique with a cache/key algorithm
|
||||
*/
|
||||
function getCachedPoint(phash, p) {
|
||||
let cached = phash[p.key];
|
||||
if (!cached) {
|
||||
phash[p.key] = p;
|
||||
return p;
|
||||
}
|
||||
return cached;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given two points and hints about their edges,
|
||||
* return a new Line object with points sorted
|
||||
* lexicographically by key. This allows for future
|
||||
* line de-duplication and joins.
|
||||
*
|
||||
* @param {Object} phash
|
||||
* @param {Point} p1
|
||||
* @param {Point} p2
|
||||
* @param {boolean} [coplanar]
|
||||
* @param {boolean} [edge]
|
||||
* @returns {Line}
|
||||
*/
|
||||
function makeZLine(phash, p1, p2, coplanar, edge) {
|
||||
p1 = getCachedPoint(phash, p1);
|
||||
p2 = getCachedPoint(phash, p2);
|
||||
let line = newOrderedLine(p1,p2);
|
||||
line.coplanar = coplanar || false;
|
||||
line.edge = edge || false;
|
||||
return line;
|
||||
}
|
||||
|
||||
/**
|
||||
* process a single z-slice on a single mesh and
|
||||
* add to slices array
|
||||
*
|
||||
* @param {number} z
|
||||
* @param {number} [height] optional real height (fdm)
|
||||
*/
|
||||
function sliceZ(z, points, options = {}) {
|
||||
let phash = {},
|
||||
lines = [],
|
||||
p1, p2, p3;
|
||||
|
||||
// iterate over matching buckets for this z offset
|
||||
for (let i = 0; i < points.length; ) {
|
||||
p1 = points[i++];
|
||||
p2 = points[i++];
|
||||
p3 = points[i++];
|
||||
let where = {under: [], over: [], on: []};
|
||||
checkUnderOverOn(p1, z, where);
|
||||
checkUnderOverOn(p2, z, where);
|
||||
checkUnderOverOn(p3, z, where);
|
||||
if (where.under.length === 3 || where.over.length === 3) {
|
||||
// does not intersect (all 3 above or below)
|
||||
} else if (where.on.length === 2) {
|
||||
// one side of triangle is on the Z plane and 3rd is below
|
||||
// drop lines with 3rd above because that leads to ambiguities
|
||||
// with complex nested polygons on flat surface
|
||||
if (where.under.length === 1) {
|
||||
lines.push(makeZLine(phash, where.on[0], where.on[1], false, true));
|
||||
}
|
||||
} else if (where.on.length === 3) {
|
||||
// triangle is coplanar with Z
|
||||
// we drop these because this face is attached to 3 others
|
||||
// that will satisfy the if above (line) with 2 points
|
||||
} else if (where.under.length === 0 || where.over.length === 0) {
|
||||
// does not intersect but one point is on the slice Z plane
|
||||
} else {
|
||||
// compute two point intersections and construct line
|
||||
let line = intersectPoints(where.over, where.under, z);
|
||||
if (line.length < 2 && where.on.length === 1) {
|
||||
line.push(where.on[0]);
|
||||
}
|
||||
if (line.length === 2) {
|
||||
lines.push(makeZLine(phash, line[0], line[1]));
|
||||
} else {
|
||||
console.log({msg: "invalid ips", line: line, where: where});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lines.length == 0 && options.noEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
// de-dup and group lines
|
||||
lines = removeDuplicateLines(lines);
|
||||
let groups = connectLines(lines, z);
|
||||
|
||||
// simplistic healing of bad meshes
|
||||
if (options.union) {
|
||||
groups = POLY.flatten(POLY.union(POLY.nest(groups), null, true), null, true);
|
||||
}
|
||||
|
||||
// if ((debug && lines.excessive) || xray) {
|
||||
// const dash = xray || 3;
|
||||
// lines.forEach((line, i) => {
|
||||
// const group = i % dash;
|
||||
// const color = [ 0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff ][group];
|
||||
// slice.output().setLayer(`xl-${group}`, color).addLine(line.p1, line.p2);
|
||||
// });
|
||||
// }
|
||||
|
||||
let tops = POLY.nest(groups);
|
||||
|
||||
// identify and add tops to slice
|
||||
// POLY.nest(groups).forEach((poly, i) => {
|
||||
// slice.addTop(poly);
|
||||
// if (xray) {
|
||||
// const group = i % (xray || 3);
|
||||
// const color = [ 0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff ][group];
|
||||
// slice.output().setLayer(`xg-${group}`, color).addPoly(poly);
|
||||
// }
|
||||
// });
|
||||
|
||||
return { lines, groups, tops };
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ let BASE = self.base,
|
|||
POLY = BASE.polygons,
|
||||
time = UTIL.time,
|
||||
qtpi = Math.cos(Math.PI/4),
|
||||
concurrent = self.Worker ? navigator.hardwareConcurrency || 0 : 0,
|
||||
ccvalue = navigator ? navigator.hardwareConcurrency || 0 : 0,
|
||||
concurrent = self.Worker && ccvalue >= 2 ? ccvalue : 0,
|
||||
current = self.worker = {
|
||||
print: null,
|
||||
snap: null
|
||||
|
|
@ -38,7 +39,7 @@ KIRI.minions = {
|
|||
|
||||
union: function(polys, minarea) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (concurrent === 0 || polys.length * 2 < concurrent) {
|
||||
if (concurrent < 2 || polys.length * 2 < concurrent) {
|
||||
resolve(POLY.union(polys, 0, true));
|
||||
return;
|
||||
}
|
||||
|
|
@ -65,7 +66,7 @@ KIRI.minions = {
|
|||
|
||||
fill: function(polys, angle, spacing, output, minLen, maxLen) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (concurrent === 0) {
|
||||
if (concurrent < 2) {
|
||||
resolve(POLY.fillArea(polys, angle, spacing, [], minLen, maxLen));
|
||||
return;
|
||||
}
|
||||
|
|
@ -89,7 +90,7 @@ KIRI.minions = {
|
|||
|
||||
clip: function(slice, polys, lines) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (concurrent === 0) {
|
||||
if (concurrent < 2) {
|
||||
reject("concurrent clip unavaiable");
|
||||
}
|
||||
minwork.queue({
|
||||
|
|
@ -111,8 +112,40 @@ KIRI.minions = {
|
|||
});
|
||||
},
|
||||
|
||||
queue: function(work, ondone) {
|
||||
minionq.push({work, ondone});
|
||||
sliceBucket: function(bucket, options, output) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (concurrent < 2) {
|
||||
reject("concurrent slice unavaiable");
|
||||
}
|
||||
let { points, slices } = bucket;
|
||||
let i = 0, floatP = new Float32Array(points.length * 3);
|
||||
for (let p of points) {
|
||||
floatP[i++] = p.x;
|
||||
floatP[i++] = p.y;
|
||||
floatP[i++] = p.z;
|
||||
}
|
||||
minwork.queue({
|
||||
cmd: "sliceBucket",
|
||||
points: floatP,
|
||||
slices,
|
||||
options
|
||||
}, data => {
|
||||
for (let rec of KIRI.codec.decode(data.output)) {
|
||||
let { slice, tops } = rec;
|
||||
let newSlice = KIRI.newSlice(slice.z);
|
||||
newSlice.index = slice.index;
|
||||
newSlice.thick = slice.thick;
|
||||
newSlice.height = slice.height;
|
||||
newSlice.addTops(tops);
|
||||
output.push(newSlice);
|
||||
}
|
||||
resolve();
|
||||
}, [ floatP.buffer ]);
|
||||
});
|
||||
},
|
||||
|
||||
queue: function(work, ondone, direct) {
|
||||
minionq.push({work, ondone, direct});
|
||||
minwork.kick();
|
||||
},
|
||||
|
||||
|
|
@ -125,7 +158,7 @@ KIRI.minions = {
|
|||
qrec.ondone(msg.data);
|
||||
minwork.kick();
|
||||
};
|
||||
minion.postMessage(qrec.work);
|
||||
minion.postMessage(qrec.work, qrec.direct);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@
|
|||
sliceFillAngle = spro.sliceFillAngle,
|
||||
supportDensity = spro.sliceSupportDensity,
|
||||
beltfact = Math.cos(Math.PI/4),
|
||||
doConcurrent = ctrl.danger && KIRI.minions.concurrent;
|
||||
doConcurrent = ctrl.threaded && KIRI.minions.concurrent;
|
||||
|
||||
isFlat = ctrl.lineType === "flat";
|
||||
isThin = !isFlat && ctrl.lineType === "line";
|
||||
|
|
@ -155,7 +155,8 @@
|
|||
// debug: true,
|
||||
// xray: 3,
|
||||
// view: view,
|
||||
indices: spro.indices
|
||||
indices: spro.indices,
|
||||
concurrent: doConcurrent
|
||||
}, onSliceDone, onSliceUpdate);
|
||||
|
||||
function onSliceUpdate(update) {
|
||||
|
|
|
|||
|
|
@ -235,13 +235,15 @@ kiri.lang['en-us'] = {
|
|||
|
||||
lo_menu: "layout",
|
||||
|
||||
pt_menu: "parts",
|
||||
pt_menu: "slicer",
|
||||
pt_deci_s: "decimate",
|
||||
pt_deci_l: ["enable or disable point decimation","during port import. for faster slicing","and lower memory usage"],
|
||||
pt_qual_s: "quality",
|
||||
pt_qual_s: "detail",
|
||||
pt_qual_l: ["level of detail to retain","during slicing operations","lower is faster"],
|
||||
pt_heal_s: "heal mesh",
|
||||
pt_heal_l: ["attempt to heal","non-manifold meshes","adds to slicing time"],
|
||||
pt_thrd_s: "threaded",
|
||||
pt_thrd_l: ["use parallel processin","when browser permits"],
|
||||
|
||||
xp_menu: "exports",
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue