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

Function tryCollapse

js/regularize.js:392–525  ·  view source on GitHub ↗
(u, v)

Source from the content-addressed store, hash-verified

390 // unrelated texels. thinness catches it (≈ 1800 in that case) while still
391 // reporting ≈ 1.15 for an equilateral triangle, so the threshold scale is
392 // similar to the old edge-ratio metric.
393 function triAspectSq(t) {
394 const a = corners[t*3], b = corners[t*3+1], c = corners[t*3+2];
395 const ax = vertX[a], ay = vertY[a], az = vertZ[a];
396 const abx = vertX[b]-ax, aby = vertY[b]-ay, abz = vertZ[b]-az;
397 const acx = vertX[c]-ax, acy = vertY[c]-ay, acz = vertZ[c]-az;
398 const bcx = vertX[c]-vertX[b], bcy = vertY[c]-vertY[b], bcz = vertZ[c]-vertZ[b];
399 const lAB2 = abx*abx + aby*aby + abz*abz;
400 const lAC2 = acx*acx + acy*acy + acz*acz;
401 const lBC2 = bcx*bcx + bcy*bcy + bcz*bcz;
402 const lmax2 = Math.max(lAB2, lAC2, lBC2);
403 const nx = aby*acz - abz*acy;
404 const ny = abz*acx - abx*acz;
405 const nz = abx*acy - aby*acx;
406 const cross2 = nx*nx + ny*ny + nz*nz;
407 return cross2 > 0 ? lmax2 * lmax2 / cross2 : Infinity;
408 }
409
410 function countDeleted() {
411 let n = 0;
412 for (let i = 0; i < triCount; i++) if (triDeleted[i]) n++;
413 return n;
414 }
415
416 // Attempt collapse of edge (u, v). Returns true if applied.
417 function tryCollapse(u, v) {
418 if (u === v) return false;
419
420 // Sharp-edge vertices stay put — refuse the collapse outright.
421 if (frozenVert[u] || frozenVert[v]) { rejectStats.frozen++; return false; }
422
423 // Wing triangles — must be exactly 2 (manifold interior edge).
424 const wings = trianglesSharingEdge(u, v);
425 if (wings.length !== 2) { rejectStats.wingCount++; return false; }
426
427 const apexW1 = thirdVertex(wings[0], u, v);
428 const apexW2 = thirdVertex(wings[1], u, v);
429 if (apexW1 === apexW2) { rejectStats.foldedApex++; return false; }
430
431 // Two-tier gate selection. Edge-cap loosens if EITHER wing is extreme
432 // (cheap to relax — easy to recover from with re-subdivide). Normal-cap
433 // loosens only if BOTH wings are extreme (asymmetric: protects fillets).
434 const w1Asp2 = triAspectSq(wings[0]);
435 const w2Asp2 = triAspectSq(wings[1]);
436 const eitherExtreme = w1Asp2 > extremeAspect2 || w2Asp2 > extremeAspect2;
437 const bothExtreme = w1Asp2 > extremeAspect2 && w2Asp2 > extremeAspect2;
438 const effMaxLenSq = eitherExtreme ? aggressiveMaxLenSqAllowed : baseMaxLenSqAllowed;
439 const effNormalCos = bothExtreme ? aggressiveNormalDeltaCos : maxNormalDeltaCos;
440
441
442 // Link condition — vertices that share a triangle with BOTH u and v
443 // (other than the wing apexes) would become non-manifold after the merge.
444 // Stamp v's neighbours, then scan u's neighbours against the stamps.
445 stampGen++;
446 for (let s = vfHead[v]; s !== -1; s = slotNext[s]) {
447 const t = (s / 3) | 0;
448 if (triDeleted[t]) continue;
449 const a = corners[t*3], b = corners[t*3+1], c = corners[t*3+2];

Callers 1

regularizeMeshFunction · 0.85

Calls 7

trianglesSharingEdgeFunction · 0.85
thirdVertexFunction · 0.85
triAspectSqFunction · 0.85
unlinkSlotFunction · 0.85
linkSlotFunction · 0.85
recomputeFaceNormalFunction · 0.85
pushMethod · 0.80

Tested by

no test coverage detected