1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2012 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsCubic.h" 8cb93a386Sopenharmony_ci 9cb93a386Sopenharmony_cistatic bool rotate(const SkDCubic& cubic, int zero, int index, SkDCubic& rotPath) { 10cb93a386Sopenharmony_ci double dy = cubic[index].fY - cubic[zero].fY; 11cb93a386Sopenharmony_ci double dx = cubic[index].fX - cubic[zero].fX; 12cb93a386Sopenharmony_ci if (approximately_zero(dy)) { 13cb93a386Sopenharmony_ci if (approximately_zero(dx)) { 14cb93a386Sopenharmony_ci return false; 15cb93a386Sopenharmony_ci } 16cb93a386Sopenharmony_ci rotPath = cubic; 17cb93a386Sopenharmony_ci if (dy) { 18cb93a386Sopenharmony_ci rotPath[index].fY = cubic[zero].fY; 19cb93a386Sopenharmony_ci int mask = other_two(index, zero); 20cb93a386Sopenharmony_ci int side1 = index ^ mask; 21cb93a386Sopenharmony_ci int side2 = zero ^ mask; 22cb93a386Sopenharmony_ci if (approximately_equal(cubic[side1].fY, cubic[zero].fY)) { 23cb93a386Sopenharmony_ci rotPath[side1].fY = cubic[zero].fY; 24cb93a386Sopenharmony_ci } 25cb93a386Sopenharmony_ci if (approximately_equal(cubic[side2].fY, cubic[zero].fY)) { 26cb93a386Sopenharmony_ci rotPath[side2].fY = cubic[zero].fY; 27cb93a386Sopenharmony_ci } 28cb93a386Sopenharmony_ci } 29cb93a386Sopenharmony_ci return true; 30cb93a386Sopenharmony_ci } 31cb93a386Sopenharmony_ci for (int i = 0; i < 4; ++i) { 32cb93a386Sopenharmony_ci rotPath[i].fX = cubic[i].fX * dx + cubic[i].fY * dy; 33cb93a386Sopenharmony_ci rotPath[i].fY = cubic[i].fY * dx - cubic[i].fX * dy; 34cb93a386Sopenharmony_ci } 35cb93a386Sopenharmony_ci return true; 36cb93a386Sopenharmony_ci} 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci// Returns 0 if negative, 1 if zero, 2 if positive 40cb93a386Sopenharmony_cistatic int side(double x) { 41cb93a386Sopenharmony_ci return (x > 0) + (x >= 0); 42cb93a386Sopenharmony_ci} 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_ci/* Given a cubic, find the convex hull described by the end and control points. 45cb93a386Sopenharmony_ci The hull may have 3 or 4 points. Cubics that degenerate into a point or line 46cb93a386Sopenharmony_ci are not considered. 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_ci The hull is computed by assuming that three points, if unique and non-linear, 49cb93a386Sopenharmony_ci form a triangle. The fourth point may replace one of the first three, may be 50cb93a386Sopenharmony_ci discarded if in the triangle or on an edge, or may be inserted between any of 51cb93a386Sopenharmony_ci the three to form a convex quadralateral. 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_ci The indices returned in order describe the convex hull. 54cb93a386Sopenharmony_ci*/ 55cb93a386Sopenharmony_ciint SkDCubic::convexHull(char order[4]) const { 56cb93a386Sopenharmony_ci size_t index; 57cb93a386Sopenharmony_ci // find top point 58cb93a386Sopenharmony_ci size_t yMin = 0; 59cb93a386Sopenharmony_ci for (index = 1; index < 4; ++index) { 60cb93a386Sopenharmony_ci if (fPts[yMin].fY > fPts[index].fY || (fPts[yMin].fY == fPts[index].fY 61cb93a386Sopenharmony_ci && fPts[yMin].fX > fPts[index].fX)) { 62cb93a386Sopenharmony_ci yMin = index; 63cb93a386Sopenharmony_ci } 64cb93a386Sopenharmony_ci } 65cb93a386Sopenharmony_ci order[0] = yMin; 66cb93a386Sopenharmony_ci int midX = -1; 67cb93a386Sopenharmony_ci int backupYMin = -1; 68cb93a386Sopenharmony_ci for (int pass = 0; pass < 2; ++pass) { 69cb93a386Sopenharmony_ci for (index = 0; index < 4; ++index) { 70cb93a386Sopenharmony_ci if (index == yMin) { 71cb93a386Sopenharmony_ci continue; 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci // rotate line from (yMin, index) to axis 74cb93a386Sopenharmony_ci // see if remaining two points are both above or below 75cb93a386Sopenharmony_ci // use this to find mid 76cb93a386Sopenharmony_ci int mask = other_two(yMin, index); 77cb93a386Sopenharmony_ci int side1 = yMin ^ mask; 78cb93a386Sopenharmony_ci int side2 = index ^ mask; 79cb93a386Sopenharmony_ci SkDCubic rotPath; 80cb93a386Sopenharmony_ci if (!rotate(*this, yMin, index, rotPath)) { // ! if cbc[yMin]==cbc[idx] 81cb93a386Sopenharmony_ci order[1] = side1; 82cb93a386Sopenharmony_ci order[2] = side2; 83cb93a386Sopenharmony_ci return 3; 84cb93a386Sopenharmony_ci } 85cb93a386Sopenharmony_ci int sides = side(rotPath[side1].fY - rotPath[yMin].fY); 86cb93a386Sopenharmony_ci sides ^= side(rotPath[side2].fY - rotPath[yMin].fY); 87cb93a386Sopenharmony_ci if (sides == 2) { // '2' means one remaining point <0, one >0 88cb93a386Sopenharmony_ci if (midX >= 0) { 89cb93a386Sopenharmony_ci // one of the control points is equal to an end point 90cb93a386Sopenharmony_ci order[0] = 0; 91cb93a386Sopenharmony_ci order[1] = 3; 92cb93a386Sopenharmony_ci if (fPts[1] == fPts[0] || fPts[1] == fPts[3]) { 93cb93a386Sopenharmony_ci order[2] = 2; 94cb93a386Sopenharmony_ci return 3; 95cb93a386Sopenharmony_ci } 96cb93a386Sopenharmony_ci if (fPts[2] == fPts[0] || fPts[2] == fPts[3]) { 97cb93a386Sopenharmony_ci order[2] = 1; 98cb93a386Sopenharmony_ci return 3; 99cb93a386Sopenharmony_ci } 100cb93a386Sopenharmony_ci // one of the control points may be very nearly but not exactly equal -- 101cb93a386Sopenharmony_ci double dist1_0 = fPts[1].distanceSquared(fPts[0]); 102cb93a386Sopenharmony_ci double dist1_3 = fPts[1].distanceSquared(fPts[3]); 103cb93a386Sopenharmony_ci double dist2_0 = fPts[2].distanceSquared(fPts[0]); 104cb93a386Sopenharmony_ci double dist2_3 = fPts[2].distanceSquared(fPts[3]); 105cb93a386Sopenharmony_ci double smallest1distSq = std::min(dist1_0, dist1_3); 106cb93a386Sopenharmony_ci double smallest2distSq = std::min(dist2_0, dist2_3); 107cb93a386Sopenharmony_ci if (approximately_zero(std::min(smallest1distSq, smallest2distSq))) { 108cb93a386Sopenharmony_ci order[2] = smallest1distSq < smallest2distSq ? 2 : 1; 109cb93a386Sopenharmony_ci return 3; 110cb93a386Sopenharmony_ci } 111cb93a386Sopenharmony_ci } 112cb93a386Sopenharmony_ci midX = index; 113cb93a386Sopenharmony_ci } else if (sides == 0) { // '0' means both to one side or the other 114cb93a386Sopenharmony_ci backupYMin = index; 115cb93a386Sopenharmony_ci } 116cb93a386Sopenharmony_ci } 117cb93a386Sopenharmony_ci if (midX >= 0) { 118cb93a386Sopenharmony_ci break; 119cb93a386Sopenharmony_ci } 120cb93a386Sopenharmony_ci if (backupYMin < 0) { 121cb93a386Sopenharmony_ci break; 122cb93a386Sopenharmony_ci } 123cb93a386Sopenharmony_ci yMin = backupYMin; 124cb93a386Sopenharmony_ci backupYMin = -1; 125cb93a386Sopenharmony_ci } 126cb93a386Sopenharmony_ci if (midX < 0) { 127cb93a386Sopenharmony_ci midX = yMin ^ 3; // choose any other point 128cb93a386Sopenharmony_ci } 129cb93a386Sopenharmony_ci int mask = other_two(yMin, midX); 130cb93a386Sopenharmony_ci int least = yMin ^ mask; 131cb93a386Sopenharmony_ci int most = midX ^ mask; 132cb93a386Sopenharmony_ci order[0] = yMin; 133cb93a386Sopenharmony_ci order[1] = least; 134cb93a386Sopenharmony_ci 135cb93a386Sopenharmony_ci // see if mid value is on same side of line (least, most) as yMin 136cb93a386Sopenharmony_ci SkDCubic midPath; 137cb93a386Sopenharmony_ci if (!rotate(*this, least, most, midPath)) { // ! if cbc[least]==cbc[most] 138cb93a386Sopenharmony_ci order[2] = midX; 139cb93a386Sopenharmony_ci return 3; 140cb93a386Sopenharmony_ci } 141cb93a386Sopenharmony_ci int midSides = side(midPath[yMin].fY - midPath[least].fY); 142cb93a386Sopenharmony_ci midSides ^= side(midPath[midX].fY - midPath[least].fY); 143cb93a386Sopenharmony_ci if (midSides != 2) { // if mid point is not between 144cb93a386Sopenharmony_ci order[2] = most; 145cb93a386Sopenharmony_ci return 3; // result is a triangle 146cb93a386Sopenharmony_ci } 147cb93a386Sopenharmony_ci order[2] = midX; 148cb93a386Sopenharmony_ci order[3] = most; 149cb93a386Sopenharmony_ci return 4; // result is a quadralateral 150cb93a386Sopenharmony_ci} 151