UNPKG

@davepagurek/flo-mat

Version:

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

123 lines (95 loc) 4.04 kB
import { allRootsCertified } from 'flo-poly'; import { getFootPointsOnBezierPolysCertified, getIntervalBox } from 'flo-bezier3'; import { Curve } from "../curve/curve.js"; import { ddDeflateWithRunningError } from './dd-deflate-with-running-error.js'; import { eDeflate } from 'flo-poly'; import { γγ } from '../error-analysis/gamma.js'; import { rootIntervalToDistanceSquaredInterval } from './root-interval-to-distance-squared-interval.js'; import { getPFromBox } from './get-p-from-box.js'; import { FootAndEndpointInfo } from './foot-and-endpoint-info.js'; const γγ3 = γγ(3); const { sqrt } = Math; /** * @internal * @param curve The curve * @param x The point from which to check * @param tRange The allowed t range * @param touchedCurve The bezier on which p is located * @param t The t value of the bezier that locates p */ function getPotentialClosestPointsOnCurveCertified( curve: Curve, x: number[], [tS,tE]: number[] = [0,1], touchedCurve: Curve | undefined = undefined, t: number | undefined = undefined, for1Prong = false, angle = 0): FootAndEndpointInfo[] { const ps = curve.ps; const shouldDeflate = angle === 0 && curve === touchedCurve; let { polyDd: polyDdO, polyE: polyEO, getPolyExact: getPolyExactO } = getFootPointsOnBezierPolysCertified(ps, x); const def = shouldDeflate ? ddDeflateWithRunningError(polyDdO, polyEO.map(e => e/γγ3), t!) : undefined; const def2 = for1Prong && shouldDeflate ? ddDeflateWithRunningError(def!.coeffs, def!.errBound.map(e => e/γγ3), t!) : undefined; const def3 = for1Prong && shouldDeflate ? ddDeflateWithRunningError(def2!.coeffs, def2!.errBound.map(e => e/γγ3), t!) : undefined; const { polyDd, polyE, getPolyExact } = def3 !== undefined ? { polyDd: def3.coeffs, polyE: def3.errBound.map(e => e/γγ3), getPolyExact: () => eDeflate(eDeflate(eDeflate(getPolyExactO(), t!), t!), t!) } : def !== undefined ? { polyDd: def.coeffs, polyE: def.errBound.map(e => e/γγ3), getPolyExact: () => eDeflate(getPolyExactO(), t!) } : { polyDd: polyDdO, polyE: polyEO, getPolyExact: getPolyExactO }; const ris = allRootsCertified(polyDd, tS, tE, polyE, getPolyExact); const dontPush0 = ( (t === 1 && curve === touchedCurve!.next) || (t === 0 && curve === touchedCurve) ); const dontPush1 = ( (t === 0 && curve === touchedCurve!.prev) || (t === 1 && curve === touchedCurve) ); if (tS === 0) { if (!dontPush0) { ris.push({ tS: 0, tE: 0, multiplicity: 1 }); } } else if (tS === 1) { if (!dontPush1) { ris.push({ tS: 1, tE: 1, multiplicity: 1 }); } } else { ris.push({ tS: tS, tE: tS, multiplicity: 1 }); } if (tE === 0) { if (!dontPush0) { ris.push({ tS: 0, tE: 0, multiplicity: 1 }); } } else if (tE === 1) { if (!dontPush1) { ris.push({ tS: 1, tE: 1, multiplicity: 1 }); } } else { ris.push({ tS: tE, tE: tE, multiplicity: 1 }); } const infos = ris .map(ri => { const { tS: ts, tE: te } = ri; if (te < tS || ts > tE) { return undefined; } const _t = (ts + te)/2; const t = _t < 0 ? 0 : _t > 1 ? 1 : _t; const box = getIntervalBox(ps, [ts, te]); const p_ = getPFromBox(box); const dSquaredI = rootIntervalToDistanceSquaredInterval(box, x); const t_ = t === 0 ? 1 : t; const curve_ = t === 0 ? curve.prev : curve; return { curve: curve_, p: p_, t: t_, d: (sqrt(dSquaredI[0]) + sqrt(dSquaredI[1]))/2, dSquaredI, box, } }); const infos_ = infos.filter(info => info !== undefined) as FootAndEndpointInfo[]; return infos_; } export { getPotentialClosestPointsOnCurveCertified }