From c8fe7fb660bc2452a646072be8f1bf0cf8aa5fec Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Thu, 18 Sep 2025 21:34:44 -0400 Subject: [PATCH] extract and somewhat generalize trace_noodle --- src/kiri/mode/fdm/post.js | 263 +++++++++++--------------------------- 1 file changed, 75 insertions(+), 188 deletions(-) diff --git a/src/kiri/mode/fdm/post.js b/src/kiri/mode/fdm/post.js index 3555c3c9..1f3cbb0d 100644 --- a/src/kiri/mode/fdm/post.js +++ b/src/kiri/mode/fdm/post.js @@ -167,69 +167,78 @@ function thin_type_3(params) { let { z, top, count, offsetN, last, gaps } = params; // produce trace from outside of poly inward no more than max inset - let { noodle, remain } = top.poly.noodle(offsetN * count); + let noodleWidth = offsetN * count; + let { noodle, remain } = top.poly.noodle(noodleWidth); top.gaps = remain; - let intersectChains = true; - let maxInsetBypass = false; - let altNuSegs = true; - - let showNoodle = false; - let showMedLine = false; - let showInset = false; - let showExtrusion = true; - let showExtrudeInset = false; - let showChainRawPoints = false; - let showChainIntersect = false; - let showNuMedLine = false; + // render inset "noodle" + // shells.appendAll(noodle); let thin = top.thin_fill = []; let shells = top.shells; let sparse = top.fill_sparse = []; - let scale = 1000; + let midR = offsetN * 0.5; // nominal extrusion width let minR = midR * 0.75; // smallest interior fill or single wall width let maxR = midR * 1.5; // max double wall extrusion width let maxF = midR * 2; // max interior extrusion width + let { lines, polys } = trace_noodle(noodle, noodleWidth, minR, midR, maxR, { + brute: false, + showExtrusion: true, + showExtrudeInset: true, + showChainIntersect: false + }); + + console.log({ lines, polys }); + + POLY.setZ([...lines, ...polys], z); + thin.push(...lines); + shells.push(...polys); + + return { last, gaps }; +} + +// trace a single extrusion line around the inside of the noodle +function trace_noodle(noodle, noodleWidth, minR, midR, maxR, { + brute, + showExtrusion, + showExtrudeInset, + showChainIntersect, +}) { + let scale = 1000; + + let polys = []; + let lines = []; let insets = []; - let inset; let dstep = minR / 4; let dtotl = 0; - top.gaps = remain; - if (maxInsetBypass || intersectChains) { - inset = POLY.offset(noodle, -dstep, { - join: ClipperLib.JoinType.jtRound, - arc: (1/dstep) * 4 - }); - while (inset && inset.length) { - dtotl += dstep; - for (let p of POLY.flatten(inset, [])) { - p.dtotl = dtotl; - } - insets.push(inset); - let ps = POLY.flatten(inset); - POLY.setZ(inset, z); - if (showInset) { - shells.appendAll(inset); - } - if (intersectChains) { - break; - } - inset = POLY.offset(inset, -dstep, { - minArea: 0 - }); + let inset = POLY.offset(noodle, -dstep, { + join: ClipperLib.JoinType.jtRound, + arc: (1/dstep) * 4 + }); + while (inset && inset.length) { + dtotl += dstep; + for (let p of POLY.flatten(inset, [])) { + p.dtotl = dtotl; } + insets.push(inset); + polys.appendAll(inset); + if (!brute) { + break; + } + inset = POLY.offset(inset, -dstep, { + minArea: 0 + }); } // project from first inset and find greated offset intersection - if (maxInsetBypass) { + if (brute) { let { intersectRayLine } = base.util; let tests = insets.slice(1); let source = POLY.flatten(insets[0], []); - console.log({ source, tests }); for (let poly of source) { // segment the smallest inset and test against all other insets poly.segment(minR).forEachSegment((p1, p2) => { @@ -263,14 +272,12 @@ function thin_type_3(params) { } } if (max.int) { - thin.push(new Point(np1.x, np1.y, z)); - thin.push(new Point(max.int.x, max.int.y, z)); + lines.push(new Point(np1.x, np1.y)); + lines.push(new Point(max.int.x, max.int.y)); } }); } - - shells.appendAll(noodle); - return { last, gaps }; + return { lines, polys }; } let pointMap = new Map(); @@ -323,12 +330,10 @@ function thin_type_3(params) { return rec; } - let chains = []; let nusegs = []; // for each standalone noodle, construct medial axis // map medial axis points into de-duplicated segments - // which will be re-connected into chains for (let poly of noodle) { // scale the polygon (including inners) so the medial axis code works properly poly = poly.clone(true).scale({ x:scale, y:scale, z:scale }); @@ -343,60 +348,23 @@ function thin_type_3(params) { } } - // connect segments into chains + // break down long segments for (let seg of lineMap.values()) { let { p0, p1 } = seg; let len = seg.len = pointDist(p0, p1); - if (altNuSegs) { - // add to nusegs - if (len <= minR) { + // add to nusegs + if (len <= minR) { + nusegs.push({ p0, p1 }); + } else { + let steps = Math.ceil(len / minR) + 1; + let dx = (p1.x - p0.x) / steps; + let dy = (p1.y - p0.y) / steps; + for (let i=0; i c.total >= minR); - - // gather point offsets into shells - let zi = z; - let nuchains = []; - if (!altNuSegs) - for (let chain of chains) { - let nuchain = []; - nuchains.push(nuchain); - // zi += 0.1; - if (showChainRawPoints) - for (let pt of chain) { - shells.push(newPolygon().centerCircle(pt, pt.r ?? 0.1, 10)); - } - // draw medial axis chain - let { closed, length } = chain; - let term = closed ? length : length - 1; - let segs = []; - for (let i=0; i