in packages/maker.js/src/core/openjscad.ts [205:295]
function convertChainsTo2D<T>(convertToT: { (c: IChain, maxArcFacet: number): T }, union: IOperate<T>, subtraction: IOperate<T>, modelToExport: IModel, jsCadCagOptions: IJscadCagOptions = {}) {
const adds: { [layerId: string]: IAdd<T>[] } = {};
const status = { total: 0, complete: 0 };
function unionize(phaseStart: number, phaseSpan: number, arr: T[]) {
let result = arr.shift();
arr.forEach(el => result = union(result, el));
status.complete++;
jsCadCagOptions.statusCallback && jsCadCagOptions.statusCallback({ progress: phaseStart + phaseSpan * status.complete / status.total });
return result;
}
function subtractChains(layerId: string, cs: IChain[]) {
const subtracts: T[] = [];
cs.forEach(c => {
if (!c.endless) return;
if (c.contains) {
addChains(layerId, c.contains);
}
status.total++;
subtracts.unshift(convertToT(c, jsCadCagOptions.maxArcFacet));
});
return subtracts;
}
function addChains(layerId: string, cs: IChain[]) {
cs.forEach(c => {
if (!c.endless) return;
const add: IAdd<T> = { cag: convertToT(c, jsCadCagOptions.maxArcFacet), subtracts: [] };
if (c.contains) {
const subtracts = subtractChains(layerId, c.contains);
if (subtracts.length > 0) {
add.subtracts.push(subtracts);
}
}
status.total++;
if (!(layerId in adds)) {
adds[layerId] = [];
}
adds[layerId].unshift(add);
});
}
const options: IFindChainsOptions = {
pointMatchingDistance: jsCadCagOptions.pointMatchingDistance,
byLayers: jsCadCagOptions.byLayers,
contain: true
};
jsCadCagOptions.statusCallback && jsCadCagOptions.statusCallback({ progress: 25 });
const chainsResult = model.findChains(modelToExport, options);
if (Array.isArray(chainsResult)) {
addChains('', chainsResult);
} else {
for (let layerId in chainsResult) {
addChains(layerId, chainsResult[layerId]);
}
}
jsCadCagOptions.statusCallback && jsCadCagOptions.statusCallback({ progress: 50 });
let closedCount = 0;
for (let layerId in adds) {
closedCount += adds[layerId].length;
}
if (closedCount === 0) {
jsCadCagOptions.statusCallback && jsCadCagOptions.statusCallback({ progress: 100 });
throw ('No closed geometries found.');
}
const resultMap: { [layerId: string]: T } = {};
for (let layerId in adds) {
const flatAdds = adds[layerId].map(add => {
let result = add.cag;
add.subtracts.forEach(subtract => {
const union = unionize(50, 50, subtract);
result = subtraction(result, union);
})
return result;
});
resultMap[layerId] = unionize(50, 50, flatAdds);
}
jsCadCagOptions.statusCallback && jsCadCagOptions.statusCallback({ progress: 100 });
return options.byLayers ? resultMap : resultMap[''];
}