|  | /* | 
|  | * 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; | 
|  | if (dy) { | 
|  | rotPath[index].fY = cubic[zero].fY; | 
|  | int mask = other_two(index, zero); | 
|  | int side1 = index ^ mask; | 
|  | int side2 = zero ^ mask; | 
|  | if (approximately_equal(cubic[side1].fY, cubic[zero].fY)) { | 
|  | rotPath[side1].fY = cubic[zero].fY; | 
|  | } | 
|  | if (approximately_equal(cubic[side2].fY, cubic[zero].fY)) { | 
|  | rotPath[side2].fY = cubic[zero].fY; | 
|  | } | 
|  | } | 
|  | 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; | 
|  | } | 
|  | if (fPts[2] == fPts[0] || fPts[2] == fPts[3]) { | 
|  | order[2] = 1; | 
|  | return 3; | 
|  | } | 
|  | // one of the control points may be very nearly but not exactly equal -- | 
|  | double dist1_0 = fPts[1].distanceSquared(fPts[0]); | 
|  | double dist1_3 = fPts[1].distanceSquared(fPts[3]); | 
|  | double dist2_0 = fPts[2].distanceSquared(fPts[0]); | 
|  | double dist2_3 = fPts[2].distanceSquared(fPts[3]); | 
|  | double smallest1distSq = SkTMin(dist1_0, dist1_3); | 
|  | double smallest2distSq = SkTMin(dist2_0, dist2_3); | 
|  | if (approximately_zero(SkTMin(smallest1distSq, smallest2distSq))) { | 
|  | order[2] = smallest1distSq < smallest2distSq ? 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 | 
|  | } |