grids: review fixes -- a pierce found on the fine grid reports the one the old 64x64 walk met first (9% of pierces moved up to 1.5 mm, and callers trim the station nearest it), buildFins drops its seated part when done, gridsize's comment counts cells right

This commit is contained in:
matthewtrahan authored and Matthew Trahan committed 2026-10-14 20:30:08 -05:00
1 parent d353ca302e
commit 0a01443560
4 files changed
+43 -4

No files matched your search

+2 -1
View File
@@ -39,7 +39,7 @@ import { buildSwayBraces } from './sway.js';
import { CUT, CUTOUT_PATTERNS } from './cutout.js';
import { FIN } from './fins/config.js';
import { buildPad, PAD } from './fins/pad.js';
import { bedContact, seatedPartTris, seatingOf } from './fins/seating.js';
import { bedContact, forgetSeated, seatedPartTris, seatingOf } from './fins/seating.js';
import { lastResortWalls } from './fins/shortwalls.js';
import { fillCoverage } from './fins/fill.js';
import { buildPerpFins, PERP, propServesPatch, unservedAfterWedges, wedgeVeto } from './fins/wedges.js';
@@ -121,6 +121,7 @@ export function applyTunables(t) {
export function buildFins(topo, result, rot, opts = {}) {
const built = buildFinsAndBraces(topo, result, rot, opts);
crestPart(null); // the crest's part is only for this build (a Worker keeps no mesh)
forgetSeated(topo); // nor the seated part: a page building inline would hold it
// A piece of the part that starts in mid-air (a cut clean through, a loose
// body) needs saying no matter what was placed: see floatingPieces.
built.floating = floatingPieces(topo, result, rot);
+4
View File
@@ -29,6 +29,10 @@ export function seatedPartTris(topo, rot, offset) {
return tris;
}
/** Drop the cached copy: buildFins calls this when it finishes, so a page that
* builds inline (Suggest's finalists) doesn't hold a seated part between builds. */
export function forgetSeated(topo) { _seated.delete(topo); }
function seat(topo, rot, offset) {
const { pos, nFaces } = topo;
const { x: ox, y: oy, z: oz } = offset;
+2 -2
View File
@@ -5,8 +5,8 @@
* over the part, so a cell's share of the mesh grew with the face count and every
* query scanned it: a 250k-face figure put ~60 triangles in an average cell, and
* with a big part's many stations those scans were ~80% of an Auto build (a
* 768 mm figure, 197 s). Size the grid to the mesh instead: about FACES_PER_CELL
* faces a cell, square cells in mm, never under 64 a side (the old grid, so a
* 768 mm figure, 197 s). Size the grid to the mesh instead: as many cells as
* faces / FACES_PER_CELL, square cells in mm, never under 64 a side (the old grid, so a
* small part is bucketed no coarser than before) or above MAX_SIDE.
*
* Cells also stay at least MIN_CELL_MM wide. The box queries (nearestPart,
+35 -1
View File
@@ -265,6 +265,36 @@ export function solidClearance(topo, rot, offset, verts, rMax = 0.45) {
const clampA = (v) => Math.min(grid.NY - 1, Math.max(0, v));
const clampB = (v) => Math.min(grid.NZ - 1, Math.max(0, v));
// The first part triangle wall triangle A pierces, in the coarse grid's cell
// order -- the walk below with the box rejects, on the old 64 x 64 layout.
const coarsePierce = (A, xLo, xHi, yLo, yHi, zLo, zHi) => {
const g = grid.coarse, done = new Set();
const cA = (v) => Math.min(g.NY - 1, Math.max(0, v));
const cB = (v) => Math.min(g.NZ - 1, Math.max(0, v));
const a0 = cA(Math.floor((yLo - rMax - g.minY) * g.sy)), a1 = cA(Math.floor((yHi + rMax - g.minY) * g.sy));
const b0 = cB(Math.floor((zLo - rMax - g.minZ) * g.sz)), b1 = cB(Math.floor((zHi + rMax - g.minZ) * g.sz));
for (let a = a0; a <= a1; a++) {
for (let b = b0; b <= b1; b++) {
const c = a * g.NZ + b;
for (let i = g.start[c]; i < g.start[c + 1]; i++) {
const f = g.items[i];
if (done.has(f)) continue;
done.add(f);
const o = f * 9;
if (Math.min(pos[o], pos[o + 3], pos[o + 6]) > xHi + rMax) continue;
if (Math.max(pos[o], pos[o + 3], pos[o + 6]) < xLo - rMax) continue;
if (Math.min(pos[o + 1], pos[o + 4], pos[o + 7]) > yHi + rMax) continue;
if (Math.max(pos[o + 1], pos[o + 4], pos[o + 7]) < yLo - rMax) continue;
if (Math.min(pos[o + 2], pos[o + 5], pos[o + 8]) > zHi + rMax) continue;
if (Math.max(pos[o + 2], pos[o + 5], pos[o + 8]) < zLo - rMax) continue;
const hit = triTriPierce(A, triVerts(pos, f));
if (hit) return hit;
}
}
}
return null; // unreachable: the fine walk found a pierce among the same candidates
};
// un-rotate the solid's vertices into the mesh frame once
const mv = new Array(verts.length);
for (let i = 0; i < verts.length; i++) {
@@ -352,8 +382,12 @@ export function solidClearance(topo, rot, offset, verts, rMax = 0.45) {
// and edge-edge pair measures finite -- which is exactly how a wall
// whose end cap ran 0.85mm into a part face was certified "0.167mm
// clear" while the checker read 0.001.
const pierce = triTriPierce(A, B);
let pierce = triTriPierce(A, B);
if (pierce) {
// Which pierce is reported (callers trim the station nearest it)
// depends on the order the cells are walked. Report the one the old
// 64 x 64 walk met first, so the trim is the same at any grid size.
if (g !== grid.coarse) pierce = coarsePierce(A, xLo, xHi, yLo, yHi, zLo, zHi);
best = 0; bp = pierce; bq = pierce;
a = a1 + 1; b = b1 + 1; t = mv.length; // nothing beats zero
break;