UNPKG

@davepagurek/flo-mat

Version:

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

81 lines (61 loc) 2.25 kB
import { fromTo, dot, cross, rotate90Degrees, interpolate, translate, lineLineIntersection } from 'flo-vector2d'; import { CpNode } from '../cp-node/cp-node.js'; import { getEdgeDirection } from './get-edge-direction.js'; /** @internal */ const TOLERANCE_ADD_2PRONG = 0.01; /** @internal */ const TOLERANCE_USE_LINE = 0.0001; // else cubic /** * Returns the bezier curve from the maximal disk of one [[CpNode]] to another * [[CpNode]]'s maximal disk. * @param cpNodeFrom * @param cpNodeTo */ function getCurveBetween( cpNodeFrom: CpNode, cpNodeTo: CpNode): number[][] { const fromCc = cpNodeFrom.cp.circle.center; const fromL = getEdgeDirection(cpNodeFrom); const toCc = cpNodeTo.cp.circle.center; const toL = getEdgeDirection(cpNodeTo.prevOnCircle); const mid = lineLineIntersection(fromL, toL); const c = fromTo(fromCc,toCc); let twisted: boolean; if (!mid) { twisted = true; } else { const a = fromTo(fromCc, mid); const b = fromTo(toCc, mid); twisted = dot(a,c) < 0 || dot(b,c) > 0; } if (!twisted) { return [fromCc, mid!, toCc]; } const r = rotate90Degrees(c); const w1 = fromTo(fromL[0], fromL[1]); // This is a unit vector const w2 = fromTo(toL[0], toL[1]); // This is a unit vector const d1 = Math.abs(cross(c, w1)) / (3*3); const d2 = Math.abs(cross(c, w2)) / (3*3); if (d1 > TOLERANCE_ADD_2PRONG || d2 > TOLERANCE_ADD_2PRONG) { // TODO - not within tolerance - must add additional 2-prong return [fromCc, toCc]; } if (d1 > TOLERANCE_USE_LINE || d2 > TOLERANCE_USE_LINE) { // approximate with cubic bezier const m1 = interpolate(fromCc,toCc,1/3); const m2 = interpolate(fromCc,toCc,2/3); const v1 = translate(r, m1); const v2 = translate(r, m2); const l1 = [m1,v1]; const l2 = [m2,v2]; const mid1 = lineLineIntersection(fromL, l1)!; const mid2 = lineLineIntersection(toL, l2)!; return [fromCc, mid1, mid2, toCc]; } // Within tolerance - approximate with a straight line. return [fromCc, toCc]; } export { getCurveBetween }