MCPcopy Create free account
hub / github.com/CNCKitchen/stlTexturizer / regularizeMesh

Function regularizeMesh

js/regularize.js:52–526  ·  view source on GitHub ↗
(geometry, faceParentId, maxEdgeLength, opts = {})

Source from the content-addressed store, hash-verified

50 * excludeWeight-marked faces so untextured surfaces are never modified (beta)
51 * @returns {{ geometry, faceParentId, collapseCount }}
52 */
53
54import { THREE } from './threeCompat.js';
55import { QuantizedPointMap } from './meshIndex.js';
56
57const QUANTISE = 1e5;
58
59export function regularizeMesh(geometry, faceParentId, maxEdgeLength, opts = {}) {
60 // Candidate filter — triangles with thinness ABOVE this become collapse
61 // candidates. Bumped from 3 → 5 when we switched from edge-ratio to
62 // thinness: the new metric is more sensitive (catches near-collinear
63 // tris), so 3 swept up moderate-shape fillet triangles and broke them.
64 // 5 still catches every meaningful sliver — chain slivers routinely have
65 // thinness > 50 and the user's reported case was ≈ 1800.
66 const aspectThreshold = opts.aspectThreshold ?? 5;
67 // Two-tier slack. The BASE (slack) is already loose so non-sliver boundary
68 // collapses still succeed — that's what gives sliver chains the topological
69 // room to dissolve. The AGGRESSIVE tier kicks in when at least one wing is
70 // an extreme sliver and adds extra leeway on top, letting tough chain ends
71 // clear that the base tier alone wouldn't reach. An earlier attempt with a
72 // tight base (1.2) BLOCKED the helper collapses and made chains worse —
73 // hence the loose base here.
74 const slack = opts.slack ?? 3.0;
75 const aggressiveSlack = opts.aggressiveSlack ?? 8.0;
76 // Note: extremeSliverAspect is measured in the new thinness metric (lmax/hmin),
77 // so a value of 8 means "longest edge is at least 8× the shortest altitude".
78 // This skips moderate-shape fillet triangles (typically thinness 2–5) so the
79 // loose aggressive normal cap doesn't bend fine fillets, while still catching
80 // every real chain sliver (thinness routinely > 50).
81 const extremeSliverAspect = opts.extremeSliverAspect ?? 8;
82 // Per-collapse normal swing is bounded by `maxNormalDeltaCos` BUT we measure
83 // the swing against each affected triangle's *original* normal (captured
84 // once before any collapse), not its current post-drift normal. Without
85 // this, multiple rounds of 15° drift each compound into >100° corner
86 // damage on 45° edges.
87 //
88 // Like edge-cap, normal-change is two-tier. The aggressive tier fires only
89 // when BOTH wings are extreme slivers (not just one) — that matches the
90 // chain-of-needles-on-a-curved-face shape but NOT the fillet-sliver-next-to-
91 // a-larger-fillet-face shape, so fine fillets keep their tight gate.
92 const maxNormalDeltaCos = opts.maxNormalDeltaCos ?? Math.cos(15 * Math.PI / 180);
93 const aggressiveNormalDeltaCos = opts.aggressiveNormalDeltaCos ?? Math.cos(25 * Math.PI / 180);
94 // Vertices on edges with dihedral > sharpEdgeAngle are frozen: they cannot
95 // be collapse endpoints, so 45°/90° feature edges keep every original
96 // vertex. Slivers in the interior of a flat face are still collapsible.
97 const sharpEdgeCos = opts.sharpEdgeCos ?? Math.cos(30 * Math.PI / 180);
98 const maxRounds = opts.maxRounds ?? 8;
99
100 // Squared caps precomputed for both tiers; the per-collapse logic picks one.
101 const baseMaxLenSqAllowed = (maxEdgeLength * slack) * (maxEdgeLength * slack);
102 const aggressiveMaxLenSqAllowed = (maxEdgeLength * aggressiveSlack) * (maxEdgeLength * aggressiveSlack);
103 const extremeAspect2 = extremeSliverAspect * extremeSliverAspect;
104
105 // ── Build indexed mesh ──
106 const pa = geometry.attributes.position.array;
107 const triCount = pa.length / 9;
108
109 const posMap = new QuantizedPointMap(QUANTISE, Math.min(triCount * 3, 1 << 22));

Callers 5

diag-cube.mjsFile · 0.90
diag-edge-hist.mjsFile · 0.90
diag-pipeline.mjsFile · 0.90
runExportPipelineFunction · 0.90

Calls 8

getOrSetMethod · 0.95
recomputeFaceNormalFunction · 0.85
linkSlotFunction · 0.85
triAspectSqFunction · 0.85
sqDistFunction · 0.85
tryCollapseFunction · 0.85
countDeletedFunction · 0.85
pushMethod · 0.80

Tested by

no test coverage detected