SkScalar SkPoint::distanceToLineSegmentBetweenSqd(const SkPoint& a, const SkPoint& b) const { // See comments to distanceToLineBetweenSqd. If the projection of c onto // u is between a and b then this returns the same result as that // function. Otherwise, it returns the distance to the closer of a and // b. Let the projection of v onto u be v'. There are three cases: // 1. v' points opposite to u. c is not between a and b and is closer // to a than b. // 2. v' points along u and has magnitude less than y. c is between // a and b and the distance to the segment is the same as distance // to the line ab. // 3. v' points along u and has greater magnitude than u. c is not // not between a and b and is closer to b than a. // v' = (u dot v) * u / |u|. So if (u dot v)/|u| is less than zero we're // in case 1. If (u dot v)/|u| is > |u| we are in case 3. Otherwise // we're in case 2. We actually compare (u dot v) to 0 and |u|^2 to // avoid a sqrt to compute |u|. SkVector u = b - a; SkVector v = *this - a; SkScalar uLengthSqd = u.lengthSqd(); SkScalar uDotV = SkPoint::DotProduct(u, v); if (uDotV <= 0) { return v.lengthSqd(); } else if (uDotV > uLengthSqd) { return b.distanceToSqd(*this); } else { SkScalar det = u.cross(v); return SkScalarMulDiv(det, det, uLengthSqd); } }
static void test_conic_tangents(skiatest::Reporter* reporter) { SkPoint pts[] = { { 10, 20}, {10, 20}, {20, 30}, { 10, 20}, {15, 25}, {20, 30}, { 10, 20}, {20, 30}, {20, 30} }; int count = (int) SK_ARRAY_COUNT(pts) / 3; for (int index = 0; index < count; ++index) { SkConic conic(&pts[index * 3], 0.707f); SkVector start = conic.evalTangentAt(0); SkVector mid = conic.evalTangentAt(.5f); SkVector end = conic.evalTangentAt(1); REPORTER_ASSERT(reporter, start.fX && start.fY); REPORTER_ASSERT(reporter, mid.fX && mid.fY); REPORTER_ASSERT(reporter, end.fX && end.fY); REPORTER_ASSERT(reporter, SkScalarNearlyZero(start.cross(mid))); REPORTER_ASSERT(reporter, SkScalarNearlyZero(mid.cross(end))); } }
// Compute the intersection 'p' between segments s0 and s1, if any. // 's' is the parametric value for the intersection along 's0' & 't' is the same for 's1'. // Returns false if there is no intersection. static bool compute_intersection(const InsetSegment& s0, const InsetSegment& s1, SkPoint* p, SkScalar* s, SkScalar* t) { SkVector v0 = s0.fP1 - s0.fP0; SkVector v1 = s1.fP1 - s1.fP0; SkScalar perpDot = v0.cross(v1); if (SkScalarNearlyZero(perpDot)) { // segments are parallel // check if endpoints are touching if (s0.fP1.equalsWithinTolerance(s1.fP0)) { *p = s0.fP1; *s = SK_Scalar1; *t = 0; return true; } if (s1.fP1.equalsWithinTolerance(s0.fP0)) { *p = s1.fP1; *s = 0; *t = SK_Scalar1; return true; } return false; } SkVector d = s1.fP0 - s0.fP0; SkScalar localS = d.cross(v1) / perpDot; if (localS < 0 || localS > SK_Scalar1) { return false; } SkScalar localT = d.cross(v0) / perpDot; if (localT < 0 || localT > SK_Scalar1) { return false; } v0 *= localS; *p = s0.fP0 + v0; *s = localS; *t = localT; return true; }
SkScalar SkPoint::distanceToLineBetweenSqd(const SkPoint& a, const SkPoint& b, Side* side) const { SkVector u = b - a; SkVector v = *this - a; SkScalar uLengthSqd = u.lengthSqd(); SkScalar det = u.cross(v); if (side) { SkASSERT(-1 == SkPoint::kLeft_Side && 0 == SkPoint::kOn_Side && 1 == kRight_Side); *side = (Side) SkScalarSignAsInt(det); } return SkScalarMulDiv(det, det, uLengthSqd); }
static bool is_clockwise(const SkVector& before, const SkVector& after) { return before.cross(after) > 0; }