// from http://blog.gludion.com/2009/08/distance-to-quadratic-bezier-curve.html // (currently only used by testing) double SkDQuad::nearestT(const SkDPoint& pt) const { SkDVector pos = fPts[0] - pt; // search points P of bezier curve with PM.(dP / dt) = 0 // a calculus leads to a 3d degree equation : SkDVector A = fPts[1] - fPts[0]; SkDVector B = fPts[2] - fPts[1]; B -= A; double a = B.dot(B); double b = 3 * A.dot(B); double c = 2 * A.dot(A) + pos.dot(B); double d = pos.dot(A); double ts[3]; int roots = SkDCubic::RootsValidT(a, b, c, d, ts); double d0 = pt.distanceSquared(fPts[0]); double d2 = pt.distanceSquared(fPts[2]); double distMin = SkTMin(d0, d2); int bestIndex = -1; for (int index = 0; index < roots; ++index) { SkDPoint onQuad = ptAtT(ts[index]); double dist = pt.distanceSquared(onQuad); if (distMin > dist) { distMin = dist; bestIndex = index; } } if (bestIndex >= 0) { return ts[bestIndex]; } return d0 < d2 ? 0 : 1; }
bool SkDCubic::controlsContainedByEnds() const { SkDVector startTan = fPts[1] - fPts[0]; if (startTan.fX == 0 && startTan.fY == 0) { startTan = fPts[2] - fPts[0]; } SkDVector endTan = fPts[2] - fPts[3]; if (endTan.fX == 0 && endTan.fY == 0) { endTan = fPts[1] - fPts[3]; } if (startTan.dot(endTan) >= 0) { return false; } SkDLine startEdge = {{fPts[0], fPts[0]}}; startEdge[1].fX -= startTan.fY; startEdge[1].fY += startTan.fX; SkDLine endEdge = {{fPts[3], fPts[3]}}; endEdge[1].fX -= endTan.fY; endEdge[1].fY += endTan.fX; double leftStart1 = startEdge.isLeft(fPts[1]); if (leftStart1 * startEdge.isLeft(fPts[2]) < 0) { return false; } double leftEnd1 = endEdge.isLeft(fPts[1]); if (leftEnd1 * endEdge.isLeft(fPts[2]) < 0) { return false; } return leftStart1 * leftEnd1 >= 0; }