Merge branch 'rel-4.6' into rel-4.6-support

This commit is contained in:
Stewart Allen 2026-01-06 07:03:08 -05:00
commit 86786512d5
3 changed files with 34 additions and 12 deletions

View file

@ -711,7 +711,7 @@ class Widget {
return this; return this;
} }
async shadowAt(z) { async shadowAt(z, pocket) {
let shadows = this.cache.shadows; let shadows = this.cache.shadows;
if (!shadows) { if (!shadows) {
shadows = this.cache.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 zover = Object.keys(shadows).map(v => parseFloat(v)).filter(v => v > z);
let minZabove = Math.min(Infinity, ...zover); let minZabove = Math.min(Infinity, ...zover);
// shift shadow probeline down a fraction to capture z flats with FP noise // 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) { if (minZabove < Infinity) {
shadow = POLY.union([...shadow, ...shadows[minZabove]], 0, true, { wasm: false }); shadow = POLY.union([...shadow, ...shadows[minZabove]], 0, true, { wasm: false });
// cull interior sliver voids // cull interior sliver voids
if (!pocket)
for (let poly of shadow) { for (let poly of shadow) {
if (poly.inner) { if (poly.inner) {
poly.inner = poly.inner.filter(inr => { poly.inner = poly.inner.filter(inr => {
@ -744,7 +745,7 @@ class Widget {
// create a stack of faces in 1mm increments // create a stack of faces in 1mm increments
// the stacks are then used to produce shadowlines // the stacks are then used to produce shadowlines
#ensureShadowCache() { #ensureShadowCache(pocket) {
if (this.cache.shadow) { if (this.cache.shadow) {
return 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 b = new THREE.Vector3(geo[ip++], geo[ip++], geo[ip++]);
const c = 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); const n = THREE.computeFaceNormal(a, b, c);
if (n.z < 0.001) { if ((pocket && n.z > -0.001) || (!pocket && n.z < 0.001)) {
continue; continue;
} }
const minZ = Math.floor(Math.min(a.z, b.z, c.z)); const minZ = Math.floor(Math.min(a.z, b.z, c.z));
@ -774,13 +775,13 @@ class Widget {
return this.cache.shadow = stack; return this.cache.shadow = stack;
} }
async computeShadowStack(zlist, progress) { async computeShadowStack(zlist, progress, pocket) {
let shadow_stack = this.cache.shadow_stack; let shadow_stack = this.cache.shadow_stack;
if (!shadow_stack) { if (!shadow_stack) {
shadow_stack = this.cache.shadow_stack = {}; shadow_stack = this.cache.shadow_stack = {};
} }
let work = self.kiri_worker; let work = self.kiri_worker;
let stack = this.#ensureShadowCache(); let stack = this.#ensureShadowCache(pocket);
let plist = []; let plist = [];
if (debug_shadow) console.time('seed minion buckets'); if (debug_shadow) console.time('seed minion buckets');
work.minions.broadcast('cam_shadow_stack', stack); work.minions.broadcast('cam_shadow_stack', stack);
@ -803,13 +804,14 @@ class Widget {
work.minions.broadcast('cam_shadow_stack', { clear: true }); work.minions.broadcast('cam_shadow_stack', { clear: true });
} }
computeShadowAtZ(z, ztop, cached) { // called from minion
return this.#computeShadowAt(z, ztop, cached); computeShadowAtZ(z, ztop, cached, pocket) {
return this.#computeShadowAt(z, ztop, cached, pocket);
} }
// union triangles > z (opt cap < ztop) into polygon(s) // union triangles > z (opt cap < ztop) into polygon(s)
// slice the triangle stack matchingg z then union the results // 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; let shadow_stack = this.cache.shadow_stack;
if (shadow_stack && shadow_stack[z]) { if (shadow_stack && shadow_stack[z]) {
return shadow_stack[z]; return shadow_stack[z];
@ -817,7 +819,7 @@ class Widget {
let label = `compute shadow ${z.round(2)}`; let label = `compute shadow ${z.round(2)}`;
if (debug_shadow) console.time(label); if (debug_shadow) console.time(label);
const found = []; const found = [];
const stack = cached ?? this.#ensureShadowCache(); const stack = cached ?? this.#ensureShadowCache(pocket);
let minZ = Math.floor(z); let minZ = Math.floor(z);
let maxZ = Math.ceil(z); let maxZ = Math.ceil(z);
let slices = []; let slices = [];

View file

@ -322,6 +322,11 @@ class OpArea extends CamOp {
} }
proc += pinc; proc += pinc;
progress(proc, 'trace'); 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 } else
if (mode === 'surface') { if (mode === 'surface') {
let { sr_type, sr_angle, sr_alter, tolerance } = op; let { sr_type, sr_angle, sr_alter, tolerance } = op;

View file

@ -392,6 +392,22 @@ export function fdm_slice(settings, widget, onupdate, ondone) {
} }
async function onSliceDone(slices) { 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 // alert non-manifold parts
if (healed) { if (healed) {
onupdate(null, null, "part may not be manifold"); onupdate(null, null, "part may not be manifold");
@ -1658,8 +1674,7 @@ function doSupportFill(args) {
slice.supports = supports; slice.supports = supports;
}; };
function fillSupportPolys(args) { function fillSupportPolys({ promises, polys, lineWidth, density, z, isBelt, angle, outline }) {
const { promises, polys, lineWidth, density, z, isBelt, angle, outline } = args;
// calculate fill density // calculate fill density
let spacing = lineWidth * (1 / density); let spacing = lineWidth * (1 / density);
polys.forEach(function (poly) { polys.forEach(function (poly) {