@davepagurek/flo-mat
Version:
Medial / Scale Axis Transform (MAT/SAT) Library.
54 lines (42 loc) • 1.84 kB
text/typescript
import { LlRbTree } from 'flo-ll-rb-tree';
import { Loop } from 'flo-boolean';
import { CpNode } from '../cp-node/cp-node.js';
import { getShapeBounds } from '../svg/get-shape-bounds.js';
import { getMinYPos } from '../svg/get-min-y-pos.js';
import { find2Prong } from './find-2-prong.js';
import { add2Prong } from './add-2-prong.js';
/**
* @internal
* Find and add two-prongs that remove any holes in the shape.
* @param loops The loops (that as a precondition must be ordered from
* highest (i.e. smallest y-value) topmost point loops to lowest)
* @param cpTrees
* @param extreme The maximum coordinate value used to calculate floating point
* tolerances.
*/
function findAndAddHoleClosing2Prongs(
loops: Loop[],
cpTrees: Map<Loop,LlRbTree<CpNode>>,
extreme: number) {
const bounds = getShapeBounds(loops);
const squaredDiagonalLength =
(bounds.maxX.p[0] - bounds.minX.p[0])**2 +
(bounds.maxY.p[1] - bounds.minY.p[1])**2;
// Find the topmost points on each loop.
const minYs = loops.map(getMinYPos);
// We start at 1 since 0 is the outer (root) loop
for (let k=1; k<minYs.length; k++) {
const posSource = minYs[k];
const holeClosingTwoProng = find2Prong(
0, loops, extreme, squaredDiagonalLength, cpTrees, posSource, true, k, false
);
if (!holeClosingTwoProng) {
throw new Error(`Unable to find hole-closing 2-prong`);
}
// TODO important - handle case of n-prong, i.e. more than one antipode
// - currently we only handle case of single antipode (the general case)
const { circle, zs: posAntipodes } = holeClosingTwoProng;
add2Prong(cpTrees, circle, posSource, [posAntipodes[0]], true, extreme);
}
}
export { findAndAddHoleClosing2Prongs }