UNPKG

@davepagurek/flo-mat

Version:

Medial / Scale Axis Transform (MAT/SAT) Library.

98 lines (77 loc) 2.83 kB
import { hausdorffDistance } from 'flo-bezier3'; import { CpNode, getCpNodesOnCircle, isTerminating, removeCpNode } from '../cp-node/cp-node.js'; import { getBranches } from './get-branches.js'; import { getCurveToNext } from '../cp-node/get-curve-to-next.js'; import { getCurveBetween } from '../get-curve/get-curve-between.js'; import { Mat } from './mat.js'; /** * Simplifies the given MAT by replacing the piecewise quad beziers composing * the MAT with fewer ones to within a given tolerance. * @param cpNode A representation of the MAT * @param anlgeTolerance Tolerance given as the degrees difference of the unit * direction vectors at the interface between curves. A tolerance of zero means * perfect smoothness is required - defaults to 15. * @param hausdorffTolerance The approximate maximum Hausdorff Distance tolerance - * defaults to `2**-3` * @param maxIterations The max iterations, defaults to `50` */ function simplifyMat( mat: Mat, anlgeTolerance = 15, hausdorffTolerance = 2**-3, maxIterations = 50): Mat { let cpNode = mat.cpNode; // Start from a leaf while (!isTerminating(cpNode)) { cpNode = cpNode.next; } const branches = getBranches(cpNode, anlgeTolerance); const canDeletes: CpNode[] = []; for (let k=0; k<branches.length; k++) { const branch = branches[k]; // Try to remove some let j = 0; while (j < branch.length) { const i = j; while (true) { j++; if (j === branch.length) { break; } const hd = getTotalHausdorffDistance(i, j, branch, maxIterations); if (hd > hausdorffTolerance) { break; } else { canDeletes.push(branch[j]); } } if (i+1 === j) { // no simplification occured break; } } } for (const cpNode of canDeletes) { const isTerminating_ = isTerminating(cpNode); const onCircleCount = getCpNodesOnCircle(cpNode).length; if (isTerminating_ || onCircleCount !== 2) { continue; } removeCpNode(cpNode); } //return { cpNode, cpTrees: createNewCpTree(cpNode) }; return { cpNode, cpTrees: undefined! }; } function getTotalHausdorffDistance( i: number, j: number, branch: CpNode[], hausdorffSpacing: number) { const hds: number[] = []; const longCurve = getCurveBetween(branch[i], branch[j].next); for (; i<j+1; i++) { hds.push(hausdorffDistance( getCurveToNext(branch[i]), longCurve, hausdorffSpacing )); } return Math.max(...hds); } export { simplifyMat }