From 6bf15373b6960303f229fd29a38d2f509f17d51b Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Mon, 22 Sep 2025 18:07:35 -0400 Subject: [PATCH] add slice bridge annotations to slow print. fix thin shell depth for identifying outside faces --- src/kiri/mode/fdm/post.js | 47 +++++++++++++++++++++++------------- src/kiri/mode/fdm/prepare.js | 10 ++++++-- src/kiri/mode/fdm/slice.js | 13 +++++++++- 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/src/kiri/mode/fdm/post.js b/src/kiri/mode/fdm/post.js index 6f002388..9a9d43e4 100644 --- a/src/kiri/mode/fdm/post.js +++ b/src/kiri/mode/fdm/post.js @@ -169,13 +169,15 @@ function thin_type_3(params) { // produce trace from outside of poly inward no more than max inset let noodleWidth = offsetN * count; let { noodle, remain } = top.poly.noodle(noodleWidth); + for (let n of POLY.flatten(noodle).sort((a,b) => a.depth - b.depth)) { + n.shell = [1,-1][Math.floor(n.depth / 2)]; + // console.log('map', n.depth, n.shell, n.length, n.area().round(3)); + } // re-expand inner offset so fill offsets align properly with expectation remain = POLY.offset(remain, offsetN / 2); - // render inset "noodle" - // shells.appendAll(noodle); - + let debugNoodle = false; let debugRemain = false; let debugExtrusion = false; @@ -190,11 +192,14 @@ function thin_type_3(params) { let lines = []; let polys = []; - for (let i=0; i b.area() - a.area())) trace_noodle( [ n ], noodleWidth, @@ -202,7 +207,7 @@ function thin_type_3(params) { i === 0 ? midR : midR * 1.25, i === 0 ? maxR : maxF, { - shell: i + 1, + shell: n.shell, lines, polys, remain: next, @@ -234,9 +239,17 @@ function thin_type_3(params) { if (polys.length) shells.push(...polys); // create shell depth annotation that will survive serialization - top.thin_sort = traces.map(a => a.shell); + top.thin_sort = traces.map(t => t.shell); - // console.log({ this: (self.kiri_minion?.name ?? self.kiri_worker), traces }); + // remove point.segment markers for codec encoding between minion and worker + for (let trace of traces) { + for (let pt of trace) { + delete pt.s; + } + } + + // console.log({ traces: traces.map(t => [t.length, t.shell]) }); + // console.log({ this: (self.kiri_minion?.name ?? self.kiri_worker), traces, polys }); return { traces, last: remain }; } @@ -255,6 +268,8 @@ function trace_noodle(noodle, noodleWidth, minR, midR, maxR, opt = {}) { shell = 0 } = opt; + // increment shell with direction (1=outside, -1=inside) + let shellAdd = shell > 0 ? 1 : -1; let sstep = 1 / shellStep; let insets = []; let scale = 1000; @@ -265,6 +280,7 @@ function trace_noodle(noodle, noodleWidth, minR, midR, maxR, opt = {}) { join: ClipperLib.JoinType.jtRound, arc: (1/dstep) * 4 }); + while (inset && inset.length) { dtotl += dstep; for (let p of POLY.flatten(inset, [])) { @@ -434,9 +450,10 @@ function trace_noodle(noodle, noodleWidth, minR, midR, maxR, opt = {}) { if (poly.parent) { inner.push(nupoly); } + let sadd = shellAdd > 0 ? (poly.parent ? shellAdd : 0) : (poly.parent ? 0 : shellAdd); let ltpo; let trace = []; - trace.shell = poly.parent ? shell : -shell; // shell number (- for inner/hole) + trace.shell = shell + sadd; poly.segment(minR, true).forEachSegment((p1, p2) => { let np1 = { x:(p1.x+p2.x)/2, y:(p1.y+p2.y)/2 }; let len = pointDist(p1, p2); @@ -548,19 +565,15 @@ function trace_noodle(noodle, noodleWidth, minR, midR, maxR, opt = {}) { let ret = POLY.nest( POLY.flatten(setA, [], true).map(p => { return p.clean().simplify(); - }).flat() + }).flat().map(p => { + p.shell = shell + shellAdd; + return p; + }) ).filter(p => p.area() >= minArea); remain.push(...ret); } - // remove point.segment markers for codec encoding between minion and worker - for (let trace of traces) { - for (let pt of trace) { - delete pt.s; - } - } - return { lines, polys, remain, traces }; } diff --git a/src/kiri/mode/fdm/prepare.js b/src/kiri/mode/fdm/prepare.js index 55808023..96e65cdb 100644 --- a/src/kiri/mode/fdm/prepare.js +++ b/src/kiri/mode/fdm/prepare.js @@ -805,10 +805,10 @@ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) { shellOrder = {"out-in":-1,"in-out":1,"alternate":-2}[process.sliceShellOrder] || -1, sparseMult = process.outputSparseMult, coastDist = process.outputCoastDist || 0, - finishSpeed = opt.speed || process.outputFinishrate, firstShellSpeed = process.firstLayerRate, firstFillSpeed = process.firstLayerFillRate, firstPrintMult = process.firstLayerPrintMult, + finishSpeed = firstLayer ? firstShellSpeed : (opt.speed || process.outputFinishrate), printSpeed = opt.speed || (firstLayer ? firstShellSpeed : process.outputFeedrate), fillSpeed = opt.speed || opt.fillSpeed || (firstLayer ? firstFillSpeed || firstShellSpeed : process.outputFeedrate), infillSpeed = process.sliceFillRate || opt.infillSpeed || fillSpeed || printSpeed, @@ -834,15 +834,21 @@ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) { z = slice.z, lastPoly; - // support alternating shell order + // support alternating shell order if (Math.abs(shellOrder) > 1 && slice.index % 2 === 1) { shellOrder = -shellOrder; } + // update fill speed when solids detected if (slice.finishSolids) { fillSpeed = process.sliceSolidRate || finishSpeed; } + // override: adapt bridge layer speed + if (slice.isBridgeLayer) { + fillSpeed /= 2; + } + // apply first layer extrusion multipliers if (firstLayer) { fillMult *= firstPrintMult; diff --git a/src/kiri/mode/fdm/slice.js b/src/kiri/mode/fdm/slice.js index 41472f5d..8fa865d5 100644 --- a/src/kiri/mode/fdm/slice.js +++ b/src/kiri/mode/fdm/slice.js @@ -498,6 +498,7 @@ export function fdm_slice(settings, widget, onupdate, ondone) { let spaceMult = slice.index === 0 ? process.firstLayerLineMult || 1 : 1; let isBottom = slice.index < bottomLayers; let isTop = topLayers && slice.index > slices.length - topLayers - 1; + let isTopBase = isTop && slice.index === slices.length - topLayers; let isDense = range.sliceFillSparse > 0.995; let isSolid = (isBottom || ((isTop || isDense) && !vaseMode)) && !isSynth; let solidWidth = isSolid ? range.sliceFillWidth || 1 : 0; @@ -505,6 +506,10 @@ export function fdm_slice(settings, widget, onupdate, ondone) { let fillSpace = fillSpacing * spaceMult * solidWidth; doSolidLayerFill(slice, fillSpace, sliceFillAngle); } + if (isTopBase) { + // mark the first top solid supporting layer as a bridge + slice.isBridgeLayer = true; + } sliceFillAngle = (sliceFillAngle + 90.0) % 360; }, "solid layers"); @@ -1386,7 +1391,10 @@ export function projectFlats(slice, count, expand) { export function projectBridges(slice, count) { if (!slice.up || !slice.bridges) return; // these flats are marked for finishing print speed - if (slice.bridges.length) slice.finishSolids = true; + if (slice.bridges.length) { + slice.finishSolids = true; + slice.isBridgeLayer = true; + } projectSolid(slice, slice.bridges, count, true, true); }; @@ -1746,6 +1754,9 @@ function fillSupportPolys(args) { * @returns {*} */ function projectSolid(slice, polys, count, up, first) { + if (slice && !up && count === 1) { + slice.isBridgeLayer = true; + } if (!slice || count <= 0) { return; }