147 lines
4.7 KiB
JavaScript
147 lines
4.7 KiB
JavaScript
![]() |
import { measureArea } from '@jscad/modeling/src/geometries/poly3';
|
||
|
import { union, subtract } from '@jscad/modeling/src/operations/booleans';
|
||
|
|
||
|
/**
|
||
|
* @param compart true => t2 , false => t1
|
||
|
* @returns 索引
|
||
|
*/
|
||
|
function Max(arr, compart) {
|
||
|
let best = arr[0];
|
||
|
let bestIndex = 0;
|
||
|
for (let i = 1; i < arr.length; i++) {
|
||
|
let t1 = arr[i];
|
||
|
if (compart(best, t1)) {
|
||
|
best = t1;
|
||
|
bestIndex = i;
|
||
|
}
|
||
|
}
|
||
|
return bestIndex;
|
||
|
}
|
||
|
|
||
|
/** Epsilon used during determination of near zero distances.
|
||
|
* @default
|
||
|
*/
|
||
|
const EPS = 5e-2;
|
||
|
|
||
|
// //////////////////////////////
|
||
|
// tolerance: The maximum difference for each parameter allowed to be considered a match
|
||
|
class FuzzyFactory {
|
||
|
constructor(numdimensions = 3, tolerance = EPS) {
|
||
|
this.lookuptable = {};
|
||
|
this.multiplier = 1.0 / tolerance;
|
||
|
}
|
||
|
// let obj = f.lookupOrCreate([el1, el2, el3], function(elements) {/* create the new object */});
|
||
|
// Performs a fuzzy lookup of the object with the specified elements.
|
||
|
// If found, returns the existing object
|
||
|
// If not found, calls the supplied callback function which should create a new object with
|
||
|
// the specified properties. This object is inserted in the lookup database.
|
||
|
lookupOrCreate(els, object) {
|
||
|
let hash = "";
|
||
|
let multiplier = this.multiplier;
|
||
|
for (let el of els) {
|
||
|
let valueQuantized = Math.round(el * multiplier);
|
||
|
hash += valueQuantized + "/";
|
||
|
}
|
||
|
if (hash in this.lookuptable)
|
||
|
return this.lookuptable[hash];
|
||
|
else {
|
||
|
let hashparts = els.map(el => {
|
||
|
let q0 = Math.floor(el * multiplier);
|
||
|
let q1 = q0 + 1;
|
||
|
return ["" + q0 + "/", "" + q1 + "/"];
|
||
|
});
|
||
|
let numelements = els.length;
|
||
|
let numhashes = 1 << numelements;
|
||
|
for (let hashmask = 0; hashmask < numhashes; ++hashmask) {
|
||
|
let hashmaskShifted = hashmask;
|
||
|
hash = "";
|
||
|
hashparts.forEach(hashpart => {
|
||
|
hash += hashpart[hashmaskShifted & 1];
|
||
|
hashmaskShifted >>= 1;
|
||
|
});
|
||
|
this.lookuptable[hash] = object;
|
||
|
}
|
||
|
return object;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//并集path2dCsgs 差集 删除小面积结果
|
||
|
function CSGSubtract(geom, path2dCsgs) {
|
||
|
let gemUnion = path2dCsgs[0];
|
||
|
for (let i = 1; i < path2dCsgs.length; i++)
|
||
|
gemUnion = union(gemUnion, path2dCsgs[i]);
|
||
|
let newGeom = subtract(geom, gemUnion);
|
||
|
//删除小面积(只留一个)
|
||
|
{
|
||
|
let fuzz = new FuzzyFactory;
|
||
|
let vmap = new Map;
|
||
|
for (let poly of newGeom.polygons) {
|
||
|
for (let v of poly.vertices) {
|
||
|
let key = fuzz.lookupOrCreate(v, v);
|
||
|
let arr = vmap.get(key);
|
||
|
if (!arr) {
|
||
|
arr = [];
|
||
|
vmap.set(key, arr);
|
||
|
}
|
||
|
arr.push(poly);
|
||
|
v["__key__"] = key;
|
||
|
}
|
||
|
}
|
||
|
let polys = newGeom.polygons.concat();
|
||
|
let polyGroups = [];
|
||
|
let calcs = new Set;
|
||
|
while (polys.length) {
|
||
|
let poly1 = polys.pop();
|
||
|
calcs.add(poly1);
|
||
|
let polyGroup = [poly1];
|
||
|
polyGroups.push(polyGroup);
|
||
|
for (let i = 0; i < polyGroup.length; i++) {
|
||
|
let poly = polyGroup[i];
|
||
|
for (let v of poly.vertices) {
|
||
|
let key = v["__key__"];
|
||
|
let arr = vmap.get(key);
|
||
|
for (let vpoly of arr) {
|
||
|
if (calcs.has(vpoly))
|
||
|
continue;
|
||
|
calcs.add(vpoly);
|
||
|
polyGroup.push(vpoly);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// arrayRemoveIf(polys, poly => !calcs.has(poly)); //加上这个无法提高性能
|
||
|
}
|
||
|
let areas = polyGroups.map(polys => {
|
||
|
let area = 0;
|
||
|
for (let poly of polys)
|
||
|
area += measureArea(poly);
|
||
|
return area;
|
||
|
});
|
||
|
let maxIndex = Max(areas, (t1, t2) => t2 > t1);
|
||
|
newGeom.polygons = polyGroups[maxIndex];
|
||
|
}
|
||
|
return newGeom;
|
||
|
}
|
||
|
|
||
|
const ctx = self;
|
||
|
ctx.addEventListener("message", e => {
|
||
|
const [path2dCsgs, geom] = e.data;
|
||
|
try {
|
||
|
const newGeom = CSGSubtract(geom, path2dCsgs);
|
||
|
postMessage({
|
||
|
status: 0,
|
||
|
geom: newGeom
|
||
|
});
|
||
|
}
|
||
|
catch (error) {
|
||
|
postMessage({
|
||
|
status: 1,
|
||
|
error
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
var CSGSubtract_worker = {};
|
||
|
|
||
|
export { CSGSubtract_worker as default };
|
||
|
//# sourceMappingURL=CSGSubtract.worker.mjs.map
|