diff --git a/src/kiri-mode/fdm/post.js b/src/kiri-mode/fdm/post.js index bee8007b..92741492 100644 --- a/src/kiri-mode/fdm/post.js +++ b/src/kiri-mode/fdm/post.js @@ -73,6 +73,96 @@ base.slicePost.FDM = function(data, options) { delete data.groups; }; +function offset_default(params) { + let { z, top, count, top_poly, offset1, offsetN, wasm, last, gaps } = params; + // standard wall offsetting strategy + POLY.offset( + top_poly, + [-offset1, -offsetN], + { + z, + wasm, + count, + outs: top.shells, + flat: true, + call: (polys, onCount) => { + last = polys; + // mark each poly with depth (offset #) starting at 0 + for (let p of polys) { + p.depth = count - onCount; + if (p.fill_off) p.fill_off.forEach(function(pi) { + // use negative offset for inners + pi.depth = -(count - onCount); + }); + // mark inner depth to match parent + if (p.inner) { + for (let pi of p.inner) { + pi.depth = p.depth; + } + } + } + } + } + ); + return { last, gaps }; +} + +function thin_type_1(params) { + let { z, top, count, top_poly, offsetN, last, gaps } = params; + top.thin_fill = []; + top.fill_sparse = []; + let layers = POLY.inset(top_poly, offsetN, count, z, true); + last = layers.last().mid; + top.shells = layers.map(r => r.mid).flat(); + top.gaps = layers.map(r => r.gap).flat(); + let off = offsetN; + let min = off * 0.75; + let max = off * 4; + for (let poly of layers.map(r => r.gap).flat()) { + let centers = poly.centers(off/2, z, min, max, {lines:false}); + top.fill_sparse.appendAll(centers); + } + return { last, gaps }; +} + +function thin_type_2(params) { + let { z, top, count, top_poly, offset1, offsetN, last, gaps, wasm } = params; + + top.gaps = gaps; + top.thin_fill = []; + let oso = {z, count, gaps: [], outs: [], minArea: 0.05, wasm}; + POLY.offset(top_poly, [-offset1, -offsetN], oso); + + oso.outs.forEach((polys, i) => { + polys.forEach(p => { + p.depth = i; + if (p.fill_off) { + p.fill_off.forEach(pi => pi.depth = i); + } + if (p.inner) { + for (let pi of p.inner) { + pi.depth = p.depth; + } + } + top.shells.push(p); + }); + last = polys; + }); + + // slice.solids.trimmed = slice.solids.trimmed || []; + oso.gaps.forEach((polys, i) => { + let off = (i == 0 ? offset1 : offsetN); + polys = POLY.offset(polys, -off * 0.8, {z, minArea: 0, wasm}); + top.thin_fill.appendAll(cullIntersections( + fillArea(polys, 45, off/2, [], 0.01, off*2), + fillArea(polys, 135, off/2, [], 0.01, off*2), + )); + gaps.push(...polys); + }); + + return { last, gaps }; +} + /** * may run in minion or worker context. performs shell offsetting * including thin wall detection when enabled @@ -112,87 +202,20 @@ FDM.doTopShells = function(z, top, count, offset1, offsetN, fillOffset, opt = {} let dist = p.first().distTo2D(p.last()); if (dist < 1) p.open = false; } }); + let ret = { last, gaps }; switch (opt.thinType) { case "type 1": - top.thin_fill = []; - top.fill_sparse = []; - let layers = POLY.inset(top_poly, offsetN, count, z, true); - last = layers.last().mid; - top.shells = layers.map(r => r.mid).flat(); - top.gaps = layers.map(r => r.gap).flat(); - let off = offsetN; - let min = off * 0.75; - let max = off * 4; - for (let poly of layers.map(r => r.gap).flat()) { - let centers = poly.centers(off/2, z, min, max, {lines:false}); - top.fill_sparse.appendAll(centers); - // top.fill_lines.appendAll(centers); - } + ret = thin_type_1({ z, top, count, top_poly, offsetN, fillOffset }); break; case "type 2": - top.thin_fill = []; - let oso = {z, count, gaps: [], outs: [], minArea: 0.05, wasm}; - POLY.offset(top_poly, [-offset1, -offsetN], oso); - - oso.outs.forEach((polys, i) => { - polys.forEach(p => { - p.depth = i; - if (p.fill_off) { - p.fill_off.forEach(pi => pi.depth = i); - } - if (p.inner) { - for (let pi of p.inner) { - pi.depth = p.depth; - } - } - top.shells.push(p); - }); - last = polys; - }); - - // slice.solids.trimmed = slice.solids.trimmed || []; - oso.gaps.forEach((polys, i) => { - let off = (i == 0 ? offset1 : offsetN); - polys = POLY.offset(polys, -off * 0.8, {z, minArea: 0, wasm}); - top.thin_fill.appendAll(cullIntersections( - fillArea(polys, 45, off/2, [], 0.01, off*2), - fillArea(polys, 135, off/2, [], 0.01, off*2), - )); - gaps = polys; - }); + ret = thin_type_2({ z, top, count, top_poly, offset1, offsetN, fillOffset, gaps, wasm }); break; default: - // standard wall offsetting strategy - POLY.offset( - top_poly, - [-offset1, -offsetN], - { - z, - wasm, - count, - outs: top.shells, - flat: true, - call: (polys, onCount) => { - last = polys; - // mark each poly with depth (offset #) starting at 0 - for (let p of polys) { - p.depth = count - onCount; - if (p.fill_off) p.fill_off.forEach(function(pi) { - // use negative offset for inners - pi.depth = -(count - onCount); - }); - // mark inner depth to match parent - if (p.inner) { - for (let pi of p.inner) { - pi.depth = p.depth; - } - } - } - } - } - ); + ret = offset_default({ z, top, count, top_poly, offset1, offsetN, wasm }); break; } + last = ret.last || last; + gaps = ret.gaps || gaps; } } else { // no shells, just infill, is permitted diff --git a/src/kiri-mode/fdm/slice.js b/src/kiri-mode/fdm/slice.js index bd3d1b5f..b16168f7 100644 --- a/src/kiri-mode/fdm/slice.js +++ b/src/kiri-mode/fdm/slice.js @@ -1000,6 +1000,7 @@ function doRender(slice, isSynth, params, opt = {}) { if (slice.tops) // missing for supports slice.tops.forEach(top => { + console.log({ render: top }); if (isThin) output .setLayer('part', Color.part) .addPolys([top.poly]); @@ -1024,7 +1025,7 @@ function doRender(slice, isSynth, params, opt = {}) { .setLayer("thin fill", Color.thin) .addLines(top.thin_fill, vopt({ offset, height })); - if (top.gaps) output + if (top.gaps && devel) output .setLayer("gaps", Color.gaps) .addPolys(top.gaps, vopt({ offset, height, thin: true })); diff --git a/src/kiri/codec.js b/src/kiri/codec.js index 89ebc0ec..db11d16c 100644 --- a/src/kiri/codec.js +++ b/src/kiri/codec.js @@ -296,6 +296,7 @@ kiri.Top.prototype.encode = function(state) { }; if (state.full) { + // obj.gaps = encode(this.gaps, state); obj.last = encode(this.last, state); obj.shells = encode(this.shells, state); obj.fill_off = encode(this.fill_off, state); @@ -308,6 +309,7 @@ kiri.Top.prototype.encode = function(state) { registerDecoder(TYPE.TOP, function(v, state) { let top = kiri.newTop(decode(v.poly, state)); if (state.full) { + // top.gaps = decode(v.gaps, state); top.last = decode(v.last, state); top.shells = decode(v.shells, state); top.fill_off = decode(v.fill_off, state); diff --git a/src/kiri/slice.js b/src/kiri/slice.js index cca53671..d2414e75 100644 --- a/src/kiri/slice.js +++ b/src/kiri/slice.js @@ -139,22 +139,27 @@ class Slice { return this; } - addTop(poly) { - if (poly.length) { + /** + * @param {Object | Polygon} data + * @returns Slice.Top + */ + addTop(data) { + if (data.length) { // standard legacy polygon - let top = new Top(poly); - this.tops.push(top); - top.simple = poly; + let top = new Top(data); + this.tops.push(data); + top.simple = data; return top; } else { - // frop top object passed back by slicePost() - let top = new Top(poly.poly); - top.thin_fill = poly.thin_fill ? poly.thin_fill.map(p => base.newPoint(p.x,p.y,p.z)) : undefined; - top.fill_lines = poly.fill_lines; - top.fill_off = poly.fill_off; - top.last = poly.last; - top.shells = poly.shells; - top.simple = poly.simple; + // create top object from object bundle passed back by slicePost() + let top = new Top(data.poly); + top.thin_fill = data.thin_fill ? data.thin_fill.map(p => base.newPoint(p.x,p.y,p.z)) : undefined; + top.fill_lines = data.fill_lines; + top.fill_off = data.fill_off; + top.last = data.last; + top.gaps = data.gaps; + top.shells = data.shells; + top.simple = data.simple; this.tops.push(top); return top; }