From 2ca01ed004f34e22465163b9b85a8828e68e92fe Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Thu, 18 Sep 2025 19:49:06 -0400 Subject: [PATCH] add alt seg generator. prepare to drop chains --- src/kiri/mode/fdm/post.js | 295 ++++---------------------------------- 1 file changed, 24 insertions(+), 271 deletions(-) diff --git a/src/kiri/mode/fdm/post.js b/src/kiri/mode/fdm/post.js index 06ca29c1..3555c3c9 100644 --- a/src/kiri/mode/fdm/post.js +++ b/src/kiri/mode/fdm/post.js @@ -171,12 +171,9 @@ function thin_type_3(params) { top.gaps = remain; - let mergeChains = false; - let simplifyChain = false; - let shortenAtNexus = false; - let shortenEdgeSpur = false; let intersectChains = true; let maxInsetBypass = false; + let altNuSegs = true; let showNoodle = false; let showMedLine = false; @@ -184,13 +181,8 @@ function thin_type_3(params) { let showExtrusion = true; let showExtrudeInset = false; let showChainRawPoints = false; - let showChainInterpPoints = true; let showChainIntersect = false; - let showNuMedLine = true; - let showMedPoints = false; - let showMedNormals = false; - let showMedRadii = false; - let showNexuses = false; + let showNuMedLine = false; let thin = top.thin_fill = []; let shells = top.shells; @@ -200,7 +192,6 @@ function thin_type_3(params) { 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 minSpur = offsetN * 1; let insets = []; let inset; @@ -333,6 +324,7 @@ function thin_type_3(params) { } let chains = []; + let nusegs = []; // for each standalone noodle, construct medial axis // map medial axis points into de-duplicated segments @@ -355,37 +347,22 @@ function thin_type_3(params) { for (let seg of lineMap.values()) { let { p0, p1 } = seg; let len = seg.len = pointDist(p0, p1); - // filter out lines where both points' radii are under the - // minR threshold. shorten and fixup lines where minR falls - // somewhere along the gradient between ends. - if (shortenEdgeSpur) - if (p0.r < minR || p1.r < minR) { - if (p0.r > minR && len > minSpur) { - // move p1 toward p0 until minR met - let pct = (minR - p1.r) / (p0.r - p1.r); - let dx = p1.x - p0.x; - let dy = p1.y - p0.y; - p1.x -= dx * pct; - p1.y -= dy * pct; - p1.r = minR; - pointMap.delete(p1.key); - } else if (p1.r > minR && len > minSpur) { - // move p0 toward p1 until minR met - let pct = (minR - p0.r) / (p1.r - p0.r); - let dx = p0.x - p1.x; - let dy = p0.y - p1.y; - p0.x -= dx * pct; - p0.y -= dy * pct; - p0.r = minR; - pointMap.delete(p0.key); + if (altNuSegs) { + // add to nusegs + if (len <= minR) { + nusegs.push({ p0, p1 }); } else { - // both points eliminated - pointMap.delete(p0.key); - pointMap.delete(p1.key); - lineMap.delete(seg.key); - continue; + 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); - chains.sort((c1,c2) => c2.total - c1.total); - - function merge1chain() { - let clen = chains.length; - for (let i=0; i chain); - - // filter dup points from connecting ends - chains = chains.map(chain => chain.filter((v, i) => i === 0 || v !== chain[i - 1])); - - // mark closed chains - // todo use exact point match by eliminating slice above - // then later removing repeated points in the resulting chain from merges - if (mergeChains) - for (let chain of chains) { - chain.closed = (chain[0] === chain.peek()); - if (chain.closed) chain.pop(); - } - - // shorten chain length by minR distance by popping or moving points - function shorten(chain) { - for (let rem=0, i=chain.length-1; i>=1 && rem < minR; i--) { - let c1 = chain[i]; - let c2 = chain[i-1]; - let d = pointDist(c1,c2); - if (rem + d <= minR) { - chain.pop(); - rem += d; - } else { - let diff = minR - rem; - // move c1 toward c2 - let pct = diff / d; - let dx = c1.x - c2.x; - let dy = c1.y - c2.y; - chain[i] = { - x: c1.x - dx * pct, - y: c1.y - dy * pct, - r: c1.r - }; - rem = 0; - break; - } - } - } - - // shorten chains terminating at nexus by midR - if (shortenAtNexus) - for (let rec of Object.values(nexus)) { - let { point } = rec; - rec.shorts = 0; - if (rec.chains.length < 3) continue; - for (let chain of chains.filter(c => !c.closed)) { - if (pointDist(chain[0], point) < minR) { - chain.reverse(); - shorten(chain); - chain.reverse(); - rec.shorts++; - } else if (chain.peek() === point) { - shorten(chain); - rec.shorts++; - } - } - } - - if (showNexuses) - for (let rec of Object.values(nexus)) { - let { point } = rec; - shells.push(newPolygon().centerCircle(point, 0.2, 6 - rec.shorts)); - } - - // Keep endpoints; drop interior points closer than R from the last kept point. - function dropClosePoints(chain, R) { - if (!chain || chain.length <= 2 || R <= 0) { - return chain; - } - let last = chain[0]; - let out = [ last ]; - let R2 = R * R; - for (let i = 1; i < chain.length - 1; i++) { - let dx = chain[i].x - last.x, - dy = chain[i].y - last.y; - if (dx * dx + dy * dy >= R2) { - out.push(chain[i]); - last = chain[i]; - } - } - out.push(chain[chain.length - 1]); - return out; - } - - // drop chain points < minR apart - if (simplifyChain) { - chains = chains.map(chain => dropClosePoints(chain, minR)); - } - - function renderPointNormal(pt, ndx, ndy) { - if (showMedNormals) { - let xo = ndx * pt.r; - let yo = ndy * pt.r; - thin.push(new Point(pt.x + yo, pt.y - xo)); - thin.push(new Point(pt.x - yo, pt.y + xo)); - } - if (showMedRadii) { - const Sx = pt.x + ndy * pt.r; - const Sy = pt.y - ndx * pt.r; - const pop = div(pt.r); - let acc = 0; - for (let r of pop) { - const t = acc + r; - const px = Sx + -ndy * t; - const py = Sy + ndx * t; - shells.push(newPolygon().centerCircle({x:px, y:py}, r, 10)); - acc += r * 2; - } - } -} + // chains = chains.filter(c => c.total >= minR); // gather point offsets into shells let zi = z; let nuchains = []; - let nusegs = []; + if (!altNuSegs) for (let chain of chains) { let nuchain = []; nuchains.push(nuchain); @@ -672,63 +473,25 @@ function thin_type_3(params) { if (first || mid) { nuchain.push(p0); } - // for length 2, first and last segment are the same - if (showMedPoints) { - if (first) { - // todo: handle closed - shells.push(newPolygon().centerCircle(p0, p0.r/2, 10)); - } - if (mid) { - // mid segments - shells.push(newPolygon().centerCircle(p0, p0.r/2, 10)); - } - if (last) { - // todo: handle closed - shells.push(newPolygon().centerCircle(p0, p0.r/2, 10)); - if (closed) { - console.log('closed'); - } else { - shells.push(newPolygon().centerCircle(p1, p1.r/2, 10)); - } - } - } - { - // todo: handle closed - if (first) { - renderPointNormal(p0, ndx, ndy); - } - if (mid) { - renderPointNormal(p0, ((ndx + segp.ndx)/2), ((ndy + segp.ndy)/2)); - } - if (last) { - renderPointNormal(p1, ndx, ndy); - } - } // interpolate across the length of the chain segment for (let indx = 1; indx < steps; indx++) { const inc = indx * step; const cr = p0.r + dr * inc; const cx = p0.x + dx * inc; const cy = p0.y + dy * inc; - const xo = ndx * cr; - const yo = ndy * cr; - if (showChainInterpPoints) { - if (showMedPoints) { - shells.push(newPolygon().centerCircle({ x:cx, y:cy }, cr/2, 10)); - } - renderPointNormal({ x:cx, y:cy, r:cr }, ndx, ndy); - } nuchain.push({ x:cx, y:cy, r:cr }); } if (last) { nuchain.push(p1); } } - if (showNuMedLine) { - for (let i=0; i