add double precision convex test
authorcaryclark <caryclark@google.com>
Mon, 2 Mar 2015 21:02:34 +0000 (13:02 -0800)
committerCommit bot <commit-bot@chromium.org>
Mon, 2 Mar 2015 21:02:34 +0000 (13:02 -0800)
BUG=389050

Review URL: https://codereview.chromium.org/975523002

src/core/SkPath.cpp
tests/PathTest.cpp

index 738edd9..b92b47f 100644 (file)
@@ -2099,30 +2099,11 @@ static bool almost_equal(SkScalar compA, SkScalar compB) {
     return aBits < bBits + epsilon && bBits < aBits + epsilon;
 }
 
-static DirChange direction_change(const SkPoint& lastPt, const SkVector& curPt,
-                                  const SkVector& lastVec, const SkVector& curVec) {
-    SkScalar cross = SkPoint::CrossProduct(lastVec, curVec);
-
-    SkScalar smallest = SkTMin(curPt.fX, SkTMin(curPt.fY, SkTMin(lastPt.fX, lastPt.fY)));
-    SkScalar largest = SkTMax(curPt.fX, SkTMax(curPt.fY, SkTMax(lastPt.fX, lastPt.fY)));
-    largest = SkTMax(largest, -smallest);
-
-    if (!almost_equal(largest, largest + cross)) {
-        int sign = SkScalarSignAsInt(cross);
-        if (sign) {
-            return (1 == sign) ? kRight_DirChange : kLeft_DirChange;
-        }
-    }
-
-    if (!SkScalarNearlyZero(lastVec.lengthSqd(), SK_ScalarNearlyZero*SK_ScalarNearlyZero) &&
-        !SkScalarNearlyZero(curVec.lengthSqd(), SK_ScalarNearlyZero*SK_ScalarNearlyZero) &&
-        lastVec.dot(curVec) < 0.0f) {
-        return kBackwards_DirChange;
-    }
-
-    return kStraight_DirChange;
+static bool approximately_zero_when_compared_to(double x, double y) {
+    return x == 0 || fabs(x) < fabs(y * FLT_EPSILON);
 }
 
+
 // only valid for a single contour
 struct Convexicator {
     Convexicator()
@@ -2161,6 +2142,7 @@ struct Convexicator {
             if (!SkScalarIsFinite(lengthSqd)) {
                 fIsFinite = false;
             } else if (!SkScalarNearlyZero(lengthSqd, SK_ScalarNearlyZero*SK_ScalarNearlyZero)) {
+                fPriorPt = fLastPt;
                 fLastPt = fCurrPt;
                 fCurrPt = pt;
                 if (++fPtCount == 2) {
@@ -2190,6 +2172,44 @@ struct Convexicator {
         }
     }
 
+    DirChange directionChange(const SkVector& curVec) {
+        SkScalar cross = SkPoint::CrossProduct(fLastVec, curVec);
+
+        SkScalar smallest = SkTMin(fCurrPt.fX, SkTMin(fCurrPt.fY, SkTMin(fLastPt.fX, fLastPt.fY)));
+        SkScalar largest = SkTMax(fCurrPt.fX, SkTMax(fCurrPt.fY, SkTMax(fLastPt.fX, fLastPt.fY)));
+        largest = SkTMax(largest, -smallest);
+
+        if (!almost_equal(largest, largest + cross)) {
+            int sign = SkScalarSignAsInt(cross);
+            if (sign) {
+                return (1 == sign) ? kRight_DirChange : kLeft_DirChange;
+            }
+        }
+
+        if (cross) {
+            double dLastVecX = SkScalarToDouble(fLastPt.fX) - SkScalarToDouble(fPriorPt.fX);
+            double dLastVecY = SkScalarToDouble(fLastPt.fY) - SkScalarToDouble(fPriorPt.fY);
+            double dCurrVecX = SkScalarToDouble(fCurrPt.fX) - SkScalarToDouble(fLastPt.fX);
+            double dCurrVecY = SkScalarToDouble(fCurrPt.fY) - SkScalarToDouble(fLastPt.fY);
+            double dCross = dLastVecX * dCurrVecY - dLastVecY * dCurrVecX;
+            if (!approximately_zero_when_compared_to(dCross, SkScalarToDouble(largest))) {
+                int sign = SkScalarSignAsInt(SkDoubleToScalar(dCross));
+                if (sign) {
+                    return (1 == sign) ? kRight_DirChange : kLeft_DirChange;
+                }
+            }
+        }
+
+        if (!SkScalarNearlyZero(fLastVec.lengthSqd(), SK_ScalarNearlyZero*SK_ScalarNearlyZero) &&
+            !SkScalarNearlyZero(curVec.lengthSqd(), SK_ScalarNearlyZero*SK_ScalarNearlyZero) &&
+            fLastVec.dot(curVec) < 0.0f) {
+            return kBackwards_DirChange;
+        }
+
+        return kStraight_DirChange;
+    }
+
+
     bool isFinite() const {
         return fIsFinite;
     }
@@ -2201,7 +2221,7 @@ struct Convexicator {
 private:
     void addVec(const SkVector& vec) {
         SkASSERT(vec.fX || vec.fY);
-        DirChange dir = direction_change(fLastPt, fCurrPt, fLastVec, vec);
+        DirChange dir = this->directionChange(vec);
         switch (dir) {
             case kLeft_DirChange:       // fall through
             case kRight_DirChange:
@@ -2230,6 +2250,7 @@ private:
         }
     }
 
+    SkPoint             fPriorPt;
     SkPoint             fLastPt;
     SkPoint             fCurrPt;
     // fLastVec does not necessarily start at fLastPt. We only advance it when the cross product
index aeab7e6..964b7e1 100644 (file)
@@ -1076,6 +1076,34 @@ static void check_convexity(skiatest::Reporter* reporter, const SkPath& path,
     REPORTER_ASSERT(reporter, c == expected);
 }
 
+static void test_path_crbug389050(skiatest::Reporter* reporter) {
+    SkPath  tinyConvexPolygon;
+    tinyConvexPolygon.moveTo(600.131559f, 800.112512f);
+    tinyConvexPolygon.lineTo(600.161735f, 800.118627f);
+    tinyConvexPolygon.lineTo(600.148962f, 800.142338f);
+    tinyConvexPolygon.lineTo(600.134891f, 800.137724f);
+    tinyConvexPolygon.close();
+    tinyConvexPolygon.getConvexity();
+    check_convexity(reporter, tinyConvexPolygon, SkPath::kConvex_Convexity);
+    check_direction(reporter, tinyConvexPolygon, SkPath::kCW_Direction);
+
+    SkPath  platTriangle;
+    platTriangle.moveTo(0, 0);
+    platTriangle.lineTo(200, 0);
+    platTriangle.lineTo(100, 0.04f);
+    platTriangle.close();
+    platTriangle.getConvexity();
+    check_direction(reporter, platTriangle, SkPath::kCW_Direction);
+
+    platTriangle.reset();
+    platTriangle.moveTo(0, 0);
+    platTriangle.lineTo(200, 0);
+    platTriangle.lineTo(100, 0.03f);
+    platTriangle.close();
+    platTriangle.getConvexity();
+    check_direction(reporter, platTriangle, SkPath::kCW_Direction);
+}
+
 static void test_convexity2(skiatest::Reporter* reporter) {
     SkPath pt;
     pt.moveTo(0, 0);
@@ -3739,6 +3767,7 @@ DEF_TEST(Paths, reporter) {
     PathTest_Private::TestPathTo(reporter);
     PathRefTest_Private::TestPathRef(reporter);
     test_dump(reporter);
+    test_path_crbug389050(reporter);
     test_path_crbugskia2820(reporter);
     test_skbug_3469(reporter);
     test_skbug_3239(reporter);