diff --git a/src/kiri/core/widget.js b/src/kiri/core/widget.js index d7791888..ff23f145 100644 --- a/src/kiri/core/widget.js +++ b/src/kiri/core/widget.js @@ -711,7 +711,7 @@ class Widget { return this; } - async shadowAt(z) { + async shadowAt(z, pocket) { let shadows = this.cache.shadows; if (!shadows) { shadows = this.cache.shadows = {}; @@ -724,10 +724,11 @@ class Widget { let zover = Object.keys(shadows).map(v => parseFloat(v)).filter(v => v > z); let minZabove = Math.min(Infinity, ...zover); // shift shadow probeline down a fraction to capture z flats with FP noise - let shadow = this.#computeShadowAt(z - 0.005, minZabove); + let shadow = this.#computeShadowAt(z - 0.005, minZabove, undefined, pocket); if (minZabove < Infinity) { shadow = POLY.union([...shadow, ...shadows[minZabove]], 0, true, { wasm: false }); // cull interior sliver voids + if (!pocket) for (let poly of shadow) { if (poly.inner) { poly.inner = poly.inner.filter(inr => { @@ -744,7 +745,7 @@ class Widget { // create a stack of faces in 1mm increments // the stacks are then used to produce shadowlines - #ensureShadowCache() { + #ensureShadowCache(pocket) { if (this.cache.shadow) { return this.cache.shadow; } @@ -761,7 +762,7 @@ class Widget { const b = new THREE.Vector3(geo[ip++], geo[ip++], geo[ip++]); const c = new THREE.Vector3(geo[ip++], geo[ip++], geo[ip++]); const n = THREE.computeFaceNormal(a, b, c); - if (n.z < 0.001) { + if ((pocket && n.z > -0.001) || (!pocket && n.z < 0.001)) { continue; } const minZ = Math.floor(Math.min(a.z, b.z, c.z)); @@ -774,13 +775,13 @@ class Widget { return this.cache.shadow = stack; } - async computeShadowStack(zlist, progress) { + async computeShadowStack(zlist, progress, pocket) { let shadow_stack = this.cache.shadow_stack; if (!shadow_stack) { shadow_stack = this.cache.shadow_stack = {}; } let work = self.kiri_worker; - let stack = this.#ensureShadowCache(); + let stack = this.#ensureShadowCache(pocket); let plist = []; if (debug_shadow) console.time('seed minion buckets'); work.minions.broadcast('cam_shadow_stack', stack); @@ -803,13 +804,14 @@ class Widget { work.minions.broadcast('cam_shadow_stack', { clear: true }); } - computeShadowAtZ(z, ztop, cached) { - return this.#computeShadowAt(z, ztop, cached); + // called from minion + computeShadowAtZ(z, ztop, cached, pocket) { + return this.#computeShadowAt(z, ztop, cached, pocket); } // union triangles > z (opt cap < ztop) into polygon(s) // slice the triangle stack matchingg z then union the results - #computeShadowAt(z, ztop, cached) { + #computeShadowAt(z, ztop, cached, pocket) { let shadow_stack = this.cache.shadow_stack; if (shadow_stack && shadow_stack[z]) { return shadow_stack[z]; @@ -817,7 +819,7 @@ class Widget { let label = `compute shadow ${z.round(2)}`; if (debug_shadow) console.time(label); const found = []; - const stack = cached ?? this.#ensureShadowCache(); + const stack = cached ?? this.#ensureShadowCache(pocket); let minZ = Math.floor(z); let maxZ = Math.ceil(z); let slices = []; diff --git a/src/kiri/mode/cam/op-area.js b/src/kiri/mode/cam/op-area.js index 528195be..1dd68fee 100644 --- a/src/kiri/mode/cam/op-area.js +++ b/src/kiri/mode/cam/op-area.js @@ -322,6 +322,11 @@ class OpArea extends CamOp { } proc += pinc; progress(proc, 'trace'); + // legacy outline early termination b/c use of + // shadow will cause duplicate output with area + if (tr_type === 'outside' && op.drape) { + break; + } } else if (mode === 'surface') { let { sr_type, sr_angle, sr_alter, tolerance } = op; diff --git a/src/kiri/mode/fdm/slice.js b/src/kiri/mode/fdm/slice.js index d880e7a5..b202d042 100644 --- a/src/kiri/mode/fdm/slice.js +++ b/src/kiri/mode/fdm/slice.js @@ -392,6 +392,22 @@ export function fdm_slice(settings, widget, onupdate, ondone) { } async function onSliceDone(slices) { + + // new auto support demonstrator using cast shadow + if (false) { + let indices = slices.map(s => s.z);//.sort((a,b) => b-a); + + await widget.computeShadowStack(indices, prog => {}, true); + + for (let slice of slices.slice().sort((a,b) => a.z - b.z)) { + let shadow = await widget.shadowAt(slice.z, true); + // slice.supports = shadow; + slice.output() + .setLayer('shadow', 0xff0000) + .addPolys(shadow); + } + } + // alert non-manifold parts if (healed) { onupdate(null, null, "part may not be manifold"); @@ -1658,8 +1674,7 @@ function doSupportFill(args) { slice.supports = supports; }; -function fillSupportPolys(args) { - const { promises, polys, lineWidth, density, z, isBelt, angle, outline } = args; +function fillSupportPolys({ promises, polys, lineWidth, density, z, isBelt, angle, outline }) { // calculate fill density let spacing = lineWidth * (1 / density); polys.forEach(function (poly) {