Index: src/pathops/SkOpCubicHull.cpp |
diff --git a/src/pathops/SkOpCubicHull.cpp b/src/pathops/SkOpCubicHull.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..11eaa1f8a9b5060e2a7bb8870352546b15a3fbdc |
--- /dev/null |
+++ b/src/pathops/SkOpCubicHull.cpp |
@@ -0,0 +1,126 @@ |
+/* |
+ * Copyright 2012 Google Inc. |
+ * |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+#include "SkPathOpsCubic.h" |
+ |
+static bool rotate(const SkDCubic& cubic, int zero, int index, SkDCubic& rotPath) { |
+ double dy = cubic[index].fY - cubic[zero].fY; |
+ double dx = cubic[index].fX - cubic[zero].fX; |
+ if (approximately_zero(dy)) { |
+ if (approximately_zero(dx)) { |
+ return false; |
+ } |
+ rotPath = cubic; |
+ return true; |
+ } |
+ for (int index = 0; index < 4; ++index) { |
+ rotPath[index].fX = cubic[index].fX * dx + cubic[index].fY * dy; |
+ rotPath[index].fY = cubic[index].fY * dx - cubic[index].fX * dy; |
+ } |
+ return true; |
+} |
+ |
+ |
+// Returns 0 if negative, 1 if zero, 2 if positive |
+static int side(double x) { |
+ return (x > 0) + (x >= 0); |
+} |
+ |
+/* Given a cubic, find the convex hull described by the end and control points. |
+ The hull may have 3 or 4 points. Cubics that degenerate into a point or line |
+ are not considered. |
+ |
+ The hull is computed by assuming that three points, if unique and non-linear, |
+ form a triangle. The fourth point may replace one of the first three, may be |
+ discarded if in the triangle or on an edge, or may be inserted between any of |
+ the three to form a convex quadralateral. |
+ |
+ The indices returned in order describe the convex hull. |
+*/ |
+int SkDCubic::convexHull(char order[4]) const { |
+ size_t index; |
+ // find top point |
+ size_t yMin = 0; |
+ for (index = 1; index < 4; ++index) { |
+ if (fPts[yMin].fY > fPts[index].fY || (fPts[yMin].fY == fPts[index].fY |
+ && fPts[yMin].fX > fPts[index].fX)) { |
+ yMin = index; |
+ } |
+ } |
+ order[0] = yMin; |
+ int midX = -1; |
+ int backupYMin = -1; |
+ for (int pass = 0; pass < 2; ++pass) { |
+ for (index = 0; index < 4; ++index) { |
+ if (index == yMin) { |
+ continue; |
+ } |
+ // rotate line from (yMin, index) to axis |
+ // see if remaining two points are both above or below |
+ // use this to find mid |
+ int mask = other_two(yMin, index); |
+ int side1 = yMin ^ mask; |
+ int side2 = index ^ mask; |
+ SkDCubic rotPath; |
+ if (!rotate(*this, yMin, index, rotPath)) { // ! if cbc[yMin]==cbc[idx] |
+ order[1] = side1; |
+ order[2] = side2; |
+ return 3; |
+ } |
+ int sides = side(rotPath[side1].fY - rotPath[yMin].fY); |
+ sides ^= side(rotPath[side2].fY - rotPath[yMin].fY); |
+ if (sides == 2) { // '2' means one remaining point <0, one >0 |
+ if (midX >= 0) { |
+ // one of the control points is equal to an end point |
+ order[0] = 0; |
+ order[1] = 3; |
+ if (fPts[1] == fPts[0] || fPts[1] == fPts[3]) { |
+ order[2] = 2; |
+ return 3; |
+ } |
+ SkASSERT(fPts[2] == fPts[0] || fPts[2] == fPts[3]); |
+ order[2] = 1; |
+ return 3; |
+ } |
+ midX = index; |
+ } else if (sides == 0) { // '0' means both to one side or the other |
+ backupYMin = index; |
+ } |
+ } |
+ if (midX >= 0) { |
+ break; |
+ } |
+ if (backupYMin < 0) { |
+ break; |
+ } |
+ yMin = backupYMin; |
+ backupYMin = -1; |
+ } |
+ if (midX < 0) { |
+ midX = yMin ^ 3; // choose any other point |
+ } |
+ int mask = other_two(yMin, midX); |
+ int least = yMin ^ mask; |
+ int most = midX ^ mask; |
+ order[0] = yMin; |
+ order[1] = least; |
+ |
+ // see if mid value is on same side of line (least, most) as yMin |
+ SkDCubic midPath; |
+ if (!rotate(*this, least, most, midPath)) { // ! if cbc[least]==cbc[most] |
+ order[2] = midX; |
+ return 3; |
+ } |
+ int midSides = side(midPath[yMin].fY - midPath[least].fY); |
+ midSides ^= side(midPath[midX].fY - midPath[least].fY); |
+ if (midSides != 2) { // if mid point is not between |
+ order[2] = most; |
+ return 3; // result is a triangle |
+ } |
+ order[2] = midX; |
+ order[3] = most; |
+ return 4; // result is a quadralateral |
+} |