/** Copyright Stewart Allen -- All Rights Reserved */ import { CamOp } from '../core/op.js'; import { newSlice } from '../../../core/slice.js'; import { newPolygon } from '../../../../geo/polygon.js'; /** * Computes the Part "shadow" and attaches relevant data to the "state" object * * The part shadow consists of top-cown layers at which the polygon shadow changes * shape. For curved or sloped surfaces, this is approximated and paths that clip * to it should use the next lower layer from current Z to ensure no part collisions. * * The shadow at each layer is computed by top-down unioning the part outline with * the shadow from the layer above. * * This operation is injected at the start of the operation chain before processing. */ class OpShadow extends CamOp { constructor(state, op) { super(state, op); } async slice(progress) { let state = this.state; let { addSlices, settings, shadowAt, unsafe, widget, workarea } = state; let { devel } = settings.controller; let bounds = widget.getBoundingBox(); let slices = []; let shadowBase; let skipTerrain = unsafe; let terrain = []; let tzindex = []; let minZ = Math.floor(bounds.min.z); let maxZ = Math.floor(bounds.max.z); for (let z = maxZ; z >= minZ; z--) { tzindex.push(z); } if (skipTerrain) { let { stock } = settings; let { center } = stock; console.log("skipping terrain generation"); shadowBase = [ newPolygon().centerRectangle(center, stock.x, stock.y) ]; tzindex = [ ]; state.shadow = { base: shadowBase, // computed shadow union at base of part holes: [], skip: skipTerrain, slices: [], // legacy / transitional stack: [], // stack of shadow slices }; return; } // distributed pre-fill shadow layer cache await widget.computeShadowStack(tzindex, prog => progress(prog / 2, 'shadow')); // terrain is the "shadow stack" where index 0 = top of part // thus array.length -1 = bottom of part for (let i=0; i p.inner || []).flat(), skip: skipTerrain, slices: slices, // legacy / transitional stack: terrain, // stack of shadow slices }; } } export { OpShadow };