move unionTris into geo/polygons as unionFaces
This commit is contained in:
parent
69ef0ff54b
commit
146c8d93b7
2 changed files with 74 additions and 68 deletions
|
|
@ -71,6 +71,7 @@ const POLYS = {
|
|||
toClipper,
|
||||
trimTo,
|
||||
union,
|
||||
unionFaces,
|
||||
xor,
|
||||
};
|
||||
|
||||
|
|
@ -487,6 +488,78 @@ export function union(polys, minarea, all, opt = {}) {
|
|||
return uset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively process triangle soup from mesh by bucketing them
|
||||
* by grid cell locality with max depth. This minimizes the number
|
||||
* of progressive small unions. Results in a few unions of larger polys.
|
||||
* Optimized for unioning 1000+ triangular faces from mesh slicing.
|
||||
*
|
||||
* @param {Polygon[]} polys - array of polygons (typically triangular faces)
|
||||
* @param {number} depth - recursion depth (internal, default 0)
|
||||
* @returns {Polygon[]} unioned polygons
|
||||
*/
|
||||
export function unionFaces(polys, depth = 0) {
|
||||
if (depth < 5 && polys.length > 1000) {
|
||||
// Calculate bounding box of all triangles
|
||||
let minX = Infinity, maxX = -Infinity;
|
||||
let minY = Infinity, maxY = -Infinity;
|
||||
for (let tri of polys) {
|
||||
for (let pt of tri.points) {
|
||||
minX = Math.min(minX, pt.x);
|
||||
maxX = Math.max(maxX, pt.x);
|
||||
minY = Math.min(minY, pt.y);
|
||||
maxY = Math.max(maxY, pt.y);
|
||||
}
|
||||
}
|
||||
|
||||
// Create NxN grid
|
||||
const gridSize = 3;
|
||||
const cellWidth = (maxX - minX) / gridSize;
|
||||
const cellHeight = (maxY - minY) / gridSize;
|
||||
|
||||
// Partition polygons into grid cells
|
||||
const grid = Array(gridSize).fill(0).map(() => Array(gridSize).fill(0).map(() => []));
|
||||
|
||||
for (let i = 0; i < polys.length; i++) {
|
||||
const poly = polys[i];
|
||||
// Use polygon centroid to assign to cell
|
||||
const bounds = poly.bounds;
|
||||
const cx = (bounds.minx + bounds.maxx) / 2;
|
||||
const cy = (bounds.miny + bounds.maxy) / 2;
|
||||
|
||||
// Clamp to grid bounds
|
||||
let gx = Math.floor((cx - minX) / cellWidth);
|
||||
let gy = Math.floor((cy - minY) / cellHeight);
|
||||
gx = Math.max(0, Math.min(gridSize - 1, gx));
|
||||
gy = Math.max(0, Math.min(gridSize - 1, gy));
|
||||
|
||||
grid[gx][gy].push(poly);
|
||||
}
|
||||
|
||||
// Union within each cell
|
||||
const cellResults = [];
|
||||
let totalInCell = 0;
|
||||
for (let gx = 0; gx < gridSize; gx++) {
|
||||
for (let gy = 0; gy < gridSize; gy++) {
|
||||
const cellPolys = grid[gx][gy];
|
||||
if (cellPolys.length > 0) {
|
||||
totalInCell += cellPolys.length;
|
||||
const cellUnion = unionFaces(cellPolys, depth + 1);
|
||||
cellResults.push(...cellUnion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Union the cell results
|
||||
polys = unionFaces(cellResults, depth + 1);
|
||||
|
||||
} else {
|
||||
polys = union(polys, 0, true, { wasm: false });
|
||||
}
|
||||
|
||||
return polys;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Polygon} poly clipping mask
|
||||
* @returns {?Polygon[]}
|
||||
|
|
|
|||
|
|
@ -965,7 +965,7 @@ class Widget {
|
|||
});
|
||||
|
||||
// recursively merge grid constrained subsets of polygons
|
||||
polys = unionTris(polys);
|
||||
polys = POLY.unionFaces(polys);
|
||||
|
||||
// for a more perfect union, pump shadows to merge very close lines
|
||||
// todo: create clipper only version that avoids round trip thru geo classes
|
||||
|
|
@ -976,73 +976,6 @@ class Widget {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* recursively process triangle soup from mesh by bucketing them
|
||||
* by grid cell locality with max depth. this minimizes the number
|
||||
* of progressive small unions. results in a few unions of larger polys.
|
||||
*/
|
||||
function unionTris(polys, depth = 0) {
|
||||
if (depth < 5 && polys.length > 1000) {
|
||||
// Calculate bounding box of all triangles
|
||||
let minX = Infinity, maxX = -Infinity;
|
||||
let minY = Infinity, maxY = -Infinity;
|
||||
for (let tri of polys) {
|
||||
for (let pt of tri.points) {
|
||||
minX = Math.min(minX, pt.x);
|
||||
maxX = Math.max(maxX, pt.x);
|
||||
minY = Math.min(minY, pt.y);
|
||||
maxY = Math.max(maxY, pt.y);
|
||||
}
|
||||
}
|
||||
|
||||
// Create NxN grid
|
||||
const gridSize = 3;
|
||||
const cellWidth = (maxX - minX) / gridSize;
|
||||
const cellHeight = (maxY - minY) / gridSize;
|
||||
|
||||
// Partition polygons into grid cells
|
||||
const grid = Array(gridSize).fill(0).map(() => Array(gridSize).fill(0).map(() => []));
|
||||
|
||||
for (let i = 0; i < polys.length; i++) {
|
||||
const poly = polys[i];
|
||||
// Use polygon centroid to assign to cell
|
||||
const bounds = poly.bounds;
|
||||
const cx = (bounds.minx + bounds.maxx) / 2;
|
||||
const cy = (bounds.miny + bounds.maxy) / 2;
|
||||
|
||||
// Clamp to grid bounds
|
||||
let gx = Math.floor((cx - minX) / cellWidth);
|
||||
let gy = Math.floor((cy - minY) / cellHeight);
|
||||
gx = Math.max(0, Math.min(gridSize - 1, gx));
|
||||
gy = Math.max(0, Math.min(gridSize - 1, gy));
|
||||
|
||||
grid[gx][gy].push(poly);
|
||||
}
|
||||
|
||||
// Union within each cell
|
||||
const cellResults = [];
|
||||
let totalInCell = 0;
|
||||
for (let gx = 0; gx < gridSize; gx++) {
|
||||
for (let gy = 0; gy < gridSize; gy++) {
|
||||
const cellPolys = grid[gx][gy];
|
||||
if (cellPolys.length > 0) {
|
||||
totalInCell += cellPolys.length;
|
||||
const cellUnion = unionTris(cellPolys, depth + 1);
|
||||
cellResults.push(...cellUnion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Union the cell results
|
||||
polys = unionTris(cellResults, depth + 1);
|
||||
|
||||
} else {
|
||||
polys = POLY.union(polys, 0, true, { wasm: false });
|
||||
}
|
||||
|
||||
return polys;
|
||||
}
|
||||
|
||||
// Widget Grouping API
|
||||
const Group = Widget.Groups = {
|
||||
list() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue