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/SkIntersections.h" 8cb93a386Sopenharmony_ci#include "src/pathops/SkLineParameters.h" 9cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsCubic.h" 10cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsCurve.h" 11cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsQuad.h" 12cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsRect.h" 13cb93a386Sopenharmony_ci 14cb93a386Sopenharmony_ci// from blackpawn.com/texts/pointinpoly 15cb93a386Sopenharmony_cistatic bool pointInTriangle(const SkDPoint fPts[3], const SkDPoint& test) { 16cb93a386Sopenharmony_ci SkDVector v0 = fPts[2] - fPts[0]; 17cb93a386Sopenharmony_ci SkDVector v1 = fPts[1] - fPts[0]; 18cb93a386Sopenharmony_ci SkDVector v2 = test - fPts[0]; 19cb93a386Sopenharmony_ci double dot00 = v0.dot(v0); 20cb93a386Sopenharmony_ci double dot01 = v0.dot(v1); 21cb93a386Sopenharmony_ci double dot02 = v0.dot(v2); 22cb93a386Sopenharmony_ci double dot11 = v1.dot(v1); 23cb93a386Sopenharmony_ci double dot12 = v1.dot(v2); 24cb93a386Sopenharmony_ci // Compute barycentric coordinates 25cb93a386Sopenharmony_ci double denom = dot00 * dot11 - dot01 * dot01; 26cb93a386Sopenharmony_ci double u = dot11 * dot02 - dot01 * dot12; 27cb93a386Sopenharmony_ci double v = dot00 * dot12 - dot01 * dot02; 28cb93a386Sopenharmony_ci // Check if point is in triangle 29cb93a386Sopenharmony_ci if (denom >= 0) { 30cb93a386Sopenharmony_ci return u >= 0 && v >= 0 && u + v < denom; 31cb93a386Sopenharmony_ci } 32cb93a386Sopenharmony_ci return u <= 0 && v <= 0 && u + v > denom; 33cb93a386Sopenharmony_ci} 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_cistatic bool matchesEnd(const SkDPoint fPts[3], const SkDPoint& test) { 36cb93a386Sopenharmony_ci return fPts[0] == test || fPts[2] == test; 37cb93a386Sopenharmony_ci} 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci/* started with at_most_end_pts_in_common from SkDQuadIntersection.cpp */ 40cb93a386Sopenharmony_ci// Do a quick reject by rotating all points relative to a line formed by 41cb93a386Sopenharmony_ci// a pair of one quad's points. If the 2nd quad's points 42cb93a386Sopenharmony_ci// are on the line or on the opposite side from the 1st quad's 'odd man', the 43cb93a386Sopenharmony_ci// curves at most intersect at the endpoints. 44cb93a386Sopenharmony_ci/* if returning true, check contains true if quad's hull collapsed, making the cubic linear 45cb93a386Sopenharmony_ci if returning false, check contains true if the the quad pair have only the end point in common 46cb93a386Sopenharmony_ci*/ 47cb93a386Sopenharmony_cibool SkDQuad::hullIntersects(const SkDQuad& q2, bool* isLinear) const { 48cb93a386Sopenharmony_ci bool linear = true; 49cb93a386Sopenharmony_ci for (int oddMan = 0; oddMan < kPointCount; ++oddMan) { 50cb93a386Sopenharmony_ci const SkDPoint* endPt[2]; 51cb93a386Sopenharmony_ci this->otherPts(oddMan, endPt); 52cb93a386Sopenharmony_ci double origX = endPt[0]->fX; 53cb93a386Sopenharmony_ci double origY = endPt[0]->fY; 54cb93a386Sopenharmony_ci double adj = endPt[1]->fX - origX; 55cb93a386Sopenharmony_ci double opp = endPt[1]->fY - origY; 56cb93a386Sopenharmony_ci double sign = (fPts[oddMan].fY - origY) * adj - (fPts[oddMan].fX - origX) * opp; 57cb93a386Sopenharmony_ci if (approximately_zero(sign)) { 58cb93a386Sopenharmony_ci continue; 59cb93a386Sopenharmony_ci } 60cb93a386Sopenharmony_ci linear = false; 61cb93a386Sopenharmony_ci bool foundOutlier = false; 62cb93a386Sopenharmony_ci for (int n = 0; n < kPointCount; ++n) { 63cb93a386Sopenharmony_ci double test = (q2[n].fY - origY) * adj - (q2[n].fX - origX) * opp; 64cb93a386Sopenharmony_ci if (test * sign > 0 && !precisely_zero(test)) { 65cb93a386Sopenharmony_ci foundOutlier = true; 66cb93a386Sopenharmony_ci break; 67cb93a386Sopenharmony_ci } 68cb93a386Sopenharmony_ci } 69cb93a386Sopenharmony_ci if (!foundOutlier) { 70cb93a386Sopenharmony_ci return false; 71cb93a386Sopenharmony_ci } 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci if (linear && !matchesEnd(fPts, q2.fPts[0]) && !matchesEnd(fPts, q2.fPts[2])) { 74cb93a386Sopenharmony_ci // if the end point of the opposite quad is inside the hull that is nearly a line, 75cb93a386Sopenharmony_ci // then representing the quad as a line may cause the intersection to be missed. 76cb93a386Sopenharmony_ci // Check to see if the endpoint is in the triangle. 77cb93a386Sopenharmony_ci if (pointInTriangle(fPts, q2.fPts[0]) || pointInTriangle(fPts, q2.fPts[2])) { 78cb93a386Sopenharmony_ci linear = false; 79cb93a386Sopenharmony_ci } 80cb93a386Sopenharmony_ci } 81cb93a386Sopenharmony_ci *isLinear = linear; 82cb93a386Sopenharmony_ci return true; 83cb93a386Sopenharmony_ci} 84cb93a386Sopenharmony_ci 85cb93a386Sopenharmony_cibool SkDQuad::hullIntersects(const SkDConic& conic, bool* isLinear) const { 86cb93a386Sopenharmony_ci return conic.hullIntersects(*this, isLinear); 87cb93a386Sopenharmony_ci} 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_cibool SkDQuad::hullIntersects(const SkDCubic& cubic, bool* isLinear) const { 90cb93a386Sopenharmony_ci return cubic.hullIntersects(*this, isLinear); 91cb93a386Sopenharmony_ci} 92cb93a386Sopenharmony_ci 93cb93a386Sopenharmony_ci/* bit twiddling for finding the off curve index (x&~m is the pair in [0,1,2] excluding oddMan) 94cb93a386Sopenharmony_cioddMan opp x=oddMan^opp x=x-oddMan m=x>>2 x&~m 95cb93a386Sopenharmony_ci 0 1 1 1 0 1 96cb93a386Sopenharmony_ci 2 2 2 0 2 97cb93a386Sopenharmony_ci 1 1 0 -1 -1 0 98cb93a386Sopenharmony_ci 2 3 2 0 2 99cb93a386Sopenharmony_ci 2 1 3 1 0 1 100cb93a386Sopenharmony_ci 2 0 -2 -1 0 101cb93a386Sopenharmony_ci*/ 102cb93a386Sopenharmony_civoid SkDQuad::otherPts(int oddMan, const SkDPoint* endPt[2]) const { 103cb93a386Sopenharmony_ci for (int opp = 1; opp < kPointCount; ++opp) { 104cb93a386Sopenharmony_ci int end = (oddMan ^ opp) - oddMan; // choose a value not equal to oddMan 105cb93a386Sopenharmony_ci end &= ~(end >> 2); // if the value went negative, set it to zero 106cb93a386Sopenharmony_ci endPt[opp - 1] = &fPts[end]; 107cb93a386Sopenharmony_ci } 108cb93a386Sopenharmony_ci} 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_ciint SkDQuad::AddValidTs(double s[], int realRoots, double* t) { 111cb93a386Sopenharmony_ci int foundRoots = 0; 112cb93a386Sopenharmony_ci for (int index = 0; index < realRoots; ++index) { 113cb93a386Sopenharmony_ci double tValue = s[index]; 114cb93a386Sopenharmony_ci if (approximately_zero_or_more(tValue) && approximately_one_or_less(tValue)) { 115cb93a386Sopenharmony_ci if (approximately_less_than_zero(tValue)) { 116cb93a386Sopenharmony_ci tValue = 0; 117cb93a386Sopenharmony_ci } else if (approximately_greater_than_one(tValue)) { 118cb93a386Sopenharmony_ci tValue = 1; 119cb93a386Sopenharmony_ci } 120cb93a386Sopenharmony_ci for (int idx2 = 0; idx2 < foundRoots; ++idx2) { 121cb93a386Sopenharmony_ci if (approximately_equal(t[idx2], tValue)) { 122cb93a386Sopenharmony_ci goto nextRoot; 123cb93a386Sopenharmony_ci } 124cb93a386Sopenharmony_ci } 125cb93a386Sopenharmony_ci t[foundRoots++] = tValue; 126cb93a386Sopenharmony_ci } 127cb93a386Sopenharmony_cinextRoot: 128cb93a386Sopenharmony_ci {} 129cb93a386Sopenharmony_ci } 130cb93a386Sopenharmony_ci return foundRoots; 131cb93a386Sopenharmony_ci} 132cb93a386Sopenharmony_ci 133cb93a386Sopenharmony_ci// note: caller expects multiple results to be sorted smaller first 134cb93a386Sopenharmony_ci// note: http://en.wikipedia.org/wiki/Loss_of_significance has an interesting 135cb93a386Sopenharmony_ci// analysis of the quadratic equation, suggesting why the following looks at 136cb93a386Sopenharmony_ci// the sign of B -- and further suggesting that the greatest loss of precision 137cb93a386Sopenharmony_ci// is in b squared less two a c 138cb93a386Sopenharmony_ciint SkDQuad::RootsValidT(double A, double B, double C, double t[2]) { 139cb93a386Sopenharmony_ci double s[2]; 140cb93a386Sopenharmony_ci int realRoots = RootsReal(A, B, C, s); 141cb93a386Sopenharmony_ci int foundRoots = AddValidTs(s, realRoots, t); 142cb93a386Sopenharmony_ci return foundRoots; 143cb93a386Sopenharmony_ci} 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_cistatic int handle_zero(const double B, const double C, double s[2]) { 146cb93a386Sopenharmony_ci if (approximately_zero(B)) { 147cb93a386Sopenharmony_ci s[0] = 0; 148cb93a386Sopenharmony_ci return C == 0; 149cb93a386Sopenharmony_ci } 150cb93a386Sopenharmony_ci s[0] = -C / B; 151cb93a386Sopenharmony_ci return 1; 152cb93a386Sopenharmony_ci} 153cb93a386Sopenharmony_ci 154cb93a386Sopenharmony_ci/* 155cb93a386Sopenharmony_ciNumeric Solutions (5.6) suggests to solve the quadratic by computing 156cb93a386Sopenharmony_ci Q = -1/2(B + sgn(B)Sqrt(B^2 - 4 A C)) 157cb93a386Sopenharmony_ciand using the roots 158cb93a386Sopenharmony_ci t1 = Q / A 159cb93a386Sopenharmony_ci t2 = C / Q 160cb93a386Sopenharmony_ci*/ 161cb93a386Sopenharmony_ci// this does not discard real roots <= 0 or >= 1 162cb93a386Sopenharmony_ciint SkDQuad::RootsReal(const double A, const double B, const double C, double s[2]) { 163cb93a386Sopenharmony_ci if (!A) { 164cb93a386Sopenharmony_ci return handle_zero(B, C, s); 165cb93a386Sopenharmony_ci } 166cb93a386Sopenharmony_ci const double p = B / (2 * A); 167cb93a386Sopenharmony_ci const double q = C / A; 168cb93a386Sopenharmony_ci if (approximately_zero(A) && (approximately_zero_inverse(p) || approximately_zero_inverse(q))) { 169cb93a386Sopenharmony_ci return handle_zero(B, C, s); 170cb93a386Sopenharmony_ci } 171cb93a386Sopenharmony_ci /* normal form: x^2 + px + q = 0 */ 172cb93a386Sopenharmony_ci const double p2 = p * p; 173cb93a386Sopenharmony_ci if (!AlmostDequalUlps(p2, q) && p2 < q) { 174cb93a386Sopenharmony_ci return 0; 175cb93a386Sopenharmony_ci } 176cb93a386Sopenharmony_ci double sqrt_D = 0; 177cb93a386Sopenharmony_ci if (p2 > q) { 178cb93a386Sopenharmony_ci sqrt_D = sqrt(p2 - q); 179cb93a386Sopenharmony_ci } 180cb93a386Sopenharmony_ci s[0] = sqrt_D - p; 181cb93a386Sopenharmony_ci s[1] = -sqrt_D - p; 182cb93a386Sopenharmony_ci return 1 + !AlmostDequalUlps(s[0], s[1]); 183cb93a386Sopenharmony_ci} 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_cibool SkDQuad::isLinear(int startIndex, int endIndex) const { 186cb93a386Sopenharmony_ci SkLineParameters lineParameters; 187cb93a386Sopenharmony_ci lineParameters.quadEndPoints(*this, startIndex, endIndex); 188cb93a386Sopenharmony_ci // FIXME: maybe it's possible to avoid this and compare non-normalized 189cb93a386Sopenharmony_ci lineParameters.normalize(); 190cb93a386Sopenharmony_ci double distance = lineParameters.controlPtDistance(*this); 191cb93a386Sopenharmony_ci double tiniest = std::min(std::min(std::min(std::min(std::min(fPts[0].fX, fPts[0].fY), 192cb93a386Sopenharmony_ci fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY); 193cb93a386Sopenharmony_ci double largest = std::max(std::max(std::max(std::max(std::max(fPts[0].fX, fPts[0].fY), 194cb93a386Sopenharmony_ci fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY); 195cb93a386Sopenharmony_ci largest = std::max(largest, -tiniest); 196cb93a386Sopenharmony_ci return approximately_zero_when_compared_to(distance, largest); 197cb93a386Sopenharmony_ci} 198cb93a386Sopenharmony_ci 199cb93a386Sopenharmony_ciSkDVector SkDQuad::dxdyAtT(double t) const { 200cb93a386Sopenharmony_ci double a = t - 1; 201cb93a386Sopenharmony_ci double b = 1 - 2 * t; 202cb93a386Sopenharmony_ci double c = t; 203cb93a386Sopenharmony_ci SkDVector result = { a * fPts[0].fX + b * fPts[1].fX + c * fPts[2].fX, 204cb93a386Sopenharmony_ci a * fPts[0].fY + b * fPts[1].fY + c * fPts[2].fY }; 205cb93a386Sopenharmony_ci if (result.fX == 0 && result.fY == 0) { 206cb93a386Sopenharmony_ci if (zero_or_one(t)) { 207cb93a386Sopenharmony_ci result = fPts[2] - fPts[0]; 208cb93a386Sopenharmony_ci } else { 209cb93a386Sopenharmony_ci // incomplete 210cb93a386Sopenharmony_ci SkDebugf("!q"); 211cb93a386Sopenharmony_ci } 212cb93a386Sopenharmony_ci } 213cb93a386Sopenharmony_ci return result; 214cb93a386Sopenharmony_ci} 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_ci// OPTIMIZE: assert if caller passes in t == 0 / t == 1 ? 217cb93a386Sopenharmony_ciSkDPoint SkDQuad::ptAtT(double t) const { 218cb93a386Sopenharmony_ci if (0 == t) { 219cb93a386Sopenharmony_ci return fPts[0]; 220cb93a386Sopenharmony_ci } 221cb93a386Sopenharmony_ci if (1 == t) { 222cb93a386Sopenharmony_ci return fPts[2]; 223cb93a386Sopenharmony_ci } 224cb93a386Sopenharmony_ci double one_t = 1 - t; 225cb93a386Sopenharmony_ci double a = one_t * one_t; 226cb93a386Sopenharmony_ci double b = 2 * one_t * t; 227cb93a386Sopenharmony_ci double c = t * t; 228cb93a386Sopenharmony_ci SkDPoint result = { a * fPts[0].fX + b * fPts[1].fX + c * fPts[2].fX, 229cb93a386Sopenharmony_ci a * fPts[0].fY + b * fPts[1].fY + c * fPts[2].fY }; 230cb93a386Sopenharmony_ci return result; 231cb93a386Sopenharmony_ci} 232cb93a386Sopenharmony_ci 233cb93a386Sopenharmony_cistatic double interp_quad_coords(const double* src, double t) { 234cb93a386Sopenharmony_ci if (0 == t) { 235cb93a386Sopenharmony_ci return src[0]; 236cb93a386Sopenharmony_ci } 237cb93a386Sopenharmony_ci if (1 == t) { 238cb93a386Sopenharmony_ci return src[4]; 239cb93a386Sopenharmony_ci } 240cb93a386Sopenharmony_ci double ab = SkDInterp(src[0], src[2], t); 241cb93a386Sopenharmony_ci double bc = SkDInterp(src[2], src[4], t); 242cb93a386Sopenharmony_ci double abc = SkDInterp(ab, bc, t); 243cb93a386Sopenharmony_ci return abc; 244cb93a386Sopenharmony_ci} 245cb93a386Sopenharmony_ci 246cb93a386Sopenharmony_cibool SkDQuad::monotonicInX() const { 247cb93a386Sopenharmony_ci return between(fPts[0].fX, fPts[1].fX, fPts[2].fX); 248cb93a386Sopenharmony_ci} 249cb93a386Sopenharmony_ci 250cb93a386Sopenharmony_cibool SkDQuad::monotonicInY() const { 251cb93a386Sopenharmony_ci return between(fPts[0].fY, fPts[1].fY, fPts[2].fY); 252cb93a386Sopenharmony_ci} 253cb93a386Sopenharmony_ci 254cb93a386Sopenharmony_ci/* 255cb93a386Sopenharmony_ciGiven a quadratic q, t1, and t2, find a small quadratic segment. 256cb93a386Sopenharmony_ci 257cb93a386Sopenharmony_ciThe new quadratic is defined by A, B, and C, where 258cb93a386Sopenharmony_ci A = c[0]*(1 - t1)*(1 - t1) + 2*c[1]*t1*(1 - t1) + c[2]*t1*t1 259cb93a386Sopenharmony_ci C = c[3]*(1 - t1)*(1 - t1) + 2*c[2]*t1*(1 - t1) + c[1]*t1*t1 260cb93a386Sopenharmony_ci 261cb93a386Sopenharmony_ciTo find B, compute the point halfway between t1 and t2: 262cb93a386Sopenharmony_ci 263cb93a386Sopenharmony_ciq(at (t1 + t2)/2) == D 264cb93a386Sopenharmony_ci 265cb93a386Sopenharmony_ciNext, compute where D must be if we know the value of B: 266cb93a386Sopenharmony_ci 267cb93a386Sopenharmony_ci_12 = A/2 + B/2 268cb93a386Sopenharmony_ci12_ = B/2 + C/2 269cb93a386Sopenharmony_ci123 = A/4 + B/2 + C/4 270cb93a386Sopenharmony_ci = D 271cb93a386Sopenharmony_ci 272cb93a386Sopenharmony_ciGroup the known values on one side: 273cb93a386Sopenharmony_ci 274cb93a386Sopenharmony_ciB = D*2 - A/2 - C/2 275cb93a386Sopenharmony_ci*/ 276cb93a386Sopenharmony_ci 277cb93a386Sopenharmony_ci// OPTIMIZE? : special case t1 = 1 && t2 = 0 278cb93a386Sopenharmony_ciSkDQuad SkDQuad::subDivide(double t1, double t2) const { 279cb93a386Sopenharmony_ci if (0 == t1 && 1 == t2) { 280cb93a386Sopenharmony_ci return *this; 281cb93a386Sopenharmony_ci } 282cb93a386Sopenharmony_ci SkDQuad dst; 283cb93a386Sopenharmony_ci double ax = dst[0].fX = interp_quad_coords(&fPts[0].fX, t1); 284cb93a386Sopenharmony_ci double ay = dst[0].fY = interp_quad_coords(&fPts[0].fY, t1); 285cb93a386Sopenharmony_ci double dx = interp_quad_coords(&fPts[0].fX, (t1 + t2) / 2); 286cb93a386Sopenharmony_ci double dy = interp_quad_coords(&fPts[0].fY, (t1 + t2) / 2); 287cb93a386Sopenharmony_ci double cx = dst[2].fX = interp_quad_coords(&fPts[0].fX, t2); 288cb93a386Sopenharmony_ci double cy = dst[2].fY = interp_quad_coords(&fPts[0].fY, t2); 289cb93a386Sopenharmony_ci /* bx = */ dst[1].fX = 2 * dx - (ax + cx) / 2; 290cb93a386Sopenharmony_ci /* by = */ dst[1].fY = 2 * dy - (ay + cy) / 2; 291cb93a386Sopenharmony_ci return dst; 292cb93a386Sopenharmony_ci} 293cb93a386Sopenharmony_ci 294cb93a386Sopenharmony_civoid SkDQuad::align(int endIndex, SkDPoint* dstPt) const { 295cb93a386Sopenharmony_ci if (fPts[endIndex].fX == fPts[1].fX) { 296cb93a386Sopenharmony_ci dstPt->fX = fPts[endIndex].fX; 297cb93a386Sopenharmony_ci } 298cb93a386Sopenharmony_ci if (fPts[endIndex].fY == fPts[1].fY) { 299cb93a386Sopenharmony_ci dstPt->fY = fPts[endIndex].fY; 300cb93a386Sopenharmony_ci } 301cb93a386Sopenharmony_ci} 302cb93a386Sopenharmony_ci 303cb93a386Sopenharmony_ciSkDPoint SkDQuad::subDivide(const SkDPoint& a, const SkDPoint& c, double t1, double t2) const { 304cb93a386Sopenharmony_ci SkASSERT(t1 != t2); 305cb93a386Sopenharmony_ci SkDPoint b; 306cb93a386Sopenharmony_ci SkDQuad sub = subDivide(t1, t2); 307cb93a386Sopenharmony_ci SkDLine b0 = {{a, sub[1] + (a - sub[0])}}; 308cb93a386Sopenharmony_ci SkDLine b1 = {{c, sub[1] + (c - sub[2])}}; 309cb93a386Sopenharmony_ci SkIntersections i; 310cb93a386Sopenharmony_ci i.intersectRay(b0, b1); 311cb93a386Sopenharmony_ci if (i.used() == 1 && i[0][0] >= 0 && i[1][0] >= 0) { 312cb93a386Sopenharmony_ci b = i.pt(0); 313cb93a386Sopenharmony_ci } else { 314cb93a386Sopenharmony_ci SkASSERT(i.used() <= 2); 315cb93a386Sopenharmony_ci return SkDPoint::Mid(b0[1], b1[1]); 316cb93a386Sopenharmony_ci } 317cb93a386Sopenharmony_ci if (t1 == 0 || t2 == 0) { 318cb93a386Sopenharmony_ci align(0, &b); 319cb93a386Sopenharmony_ci } 320cb93a386Sopenharmony_ci if (t1 == 1 || t2 == 1) { 321cb93a386Sopenharmony_ci align(2, &b); 322cb93a386Sopenharmony_ci } 323cb93a386Sopenharmony_ci if (AlmostBequalUlps(b.fX, a.fX)) { 324cb93a386Sopenharmony_ci b.fX = a.fX; 325cb93a386Sopenharmony_ci } else if (AlmostBequalUlps(b.fX, c.fX)) { 326cb93a386Sopenharmony_ci b.fX = c.fX; 327cb93a386Sopenharmony_ci } 328cb93a386Sopenharmony_ci if (AlmostBequalUlps(b.fY, a.fY)) { 329cb93a386Sopenharmony_ci b.fY = a.fY; 330cb93a386Sopenharmony_ci } else if (AlmostBequalUlps(b.fY, c.fY)) { 331cb93a386Sopenharmony_ci b.fY = c.fY; 332cb93a386Sopenharmony_ci } 333cb93a386Sopenharmony_ci return b; 334cb93a386Sopenharmony_ci} 335cb93a386Sopenharmony_ci 336cb93a386Sopenharmony_ci/* classic one t subdivision */ 337cb93a386Sopenharmony_cistatic void interp_quad_coords(const double* src, double* dst, double t) { 338cb93a386Sopenharmony_ci double ab = SkDInterp(src[0], src[2], t); 339cb93a386Sopenharmony_ci double bc = SkDInterp(src[2], src[4], t); 340cb93a386Sopenharmony_ci dst[0] = src[0]; 341cb93a386Sopenharmony_ci dst[2] = ab; 342cb93a386Sopenharmony_ci dst[4] = SkDInterp(ab, bc, t); 343cb93a386Sopenharmony_ci dst[6] = bc; 344cb93a386Sopenharmony_ci dst[8] = src[4]; 345cb93a386Sopenharmony_ci} 346cb93a386Sopenharmony_ci 347cb93a386Sopenharmony_ciSkDQuadPair SkDQuad::chopAt(double t) const 348cb93a386Sopenharmony_ci{ 349cb93a386Sopenharmony_ci SkDQuadPair dst; 350cb93a386Sopenharmony_ci interp_quad_coords(&fPts[0].fX, &dst.pts[0].fX, t); 351cb93a386Sopenharmony_ci interp_quad_coords(&fPts[0].fY, &dst.pts[0].fY, t); 352cb93a386Sopenharmony_ci return dst; 353cb93a386Sopenharmony_ci} 354cb93a386Sopenharmony_ci 355cb93a386Sopenharmony_cistatic int valid_unit_divide(double numer, double denom, double* ratio) 356cb93a386Sopenharmony_ci{ 357cb93a386Sopenharmony_ci if (numer < 0) { 358cb93a386Sopenharmony_ci numer = -numer; 359cb93a386Sopenharmony_ci denom = -denom; 360cb93a386Sopenharmony_ci } 361cb93a386Sopenharmony_ci if (denom == 0 || numer == 0 || numer >= denom) { 362cb93a386Sopenharmony_ci return 0; 363cb93a386Sopenharmony_ci } 364cb93a386Sopenharmony_ci double r = numer / denom; 365cb93a386Sopenharmony_ci if (r == 0) { // catch underflow if numer <<<< denom 366cb93a386Sopenharmony_ci return 0; 367cb93a386Sopenharmony_ci } 368cb93a386Sopenharmony_ci *ratio = r; 369cb93a386Sopenharmony_ci return 1; 370cb93a386Sopenharmony_ci} 371cb93a386Sopenharmony_ci 372cb93a386Sopenharmony_ci/** Quad'(t) = At + B, where 373cb93a386Sopenharmony_ci A = 2(a - 2b + c) 374cb93a386Sopenharmony_ci B = 2(b - a) 375cb93a386Sopenharmony_ci Solve for t, only if it fits between 0 < t < 1 376cb93a386Sopenharmony_ci*/ 377cb93a386Sopenharmony_ciint SkDQuad::FindExtrema(const double src[], double tValue[1]) { 378cb93a386Sopenharmony_ci /* At + B == 0 379cb93a386Sopenharmony_ci t = -B / A 380cb93a386Sopenharmony_ci */ 381cb93a386Sopenharmony_ci double a = src[0]; 382cb93a386Sopenharmony_ci double b = src[2]; 383cb93a386Sopenharmony_ci double c = src[4]; 384cb93a386Sopenharmony_ci return valid_unit_divide(a - b, a - b - b + c, tValue); 385cb93a386Sopenharmony_ci} 386cb93a386Sopenharmony_ci 387cb93a386Sopenharmony_ci/* Parameterization form, given A*t*t + 2*B*t*(1-t) + C*(1-t)*(1-t) 388cb93a386Sopenharmony_ci * 389cb93a386Sopenharmony_ci * a = A - 2*B + C 390cb93a386Sopenharmony_ci * b = 2*B - 2*C 391cb93a386Sopenharmony_ci * c = C 392cb93a386Sopenharmony_ci */ 393cb93a386Sopenharmony_civoid SkDQuad::SetABC(const double* quad, double* a, double* b, double* c) { 394cb93a386Sopenharmony_ci *a = quad[0]; // a = A 395cb93a386Sopenharmony_ci *b = 2 * quad[2]; // b = 2*B 396cb93a386Sopenharmony_ci *c = quad[4]; // c = C 397cb93a386Sopenharmony_ci *b -= *c; // b = 2*B - C 398cb93a386Sopenharmony_ci *a -= *b; // a = A - 2*B + C 399cb93a386Sopenharmony_ci *b -= *c; // b = 2*B - 2*C 400cb93a386Sopenharmony_ci} 401cb93a386Sopenharmony_ci 402cb93a386Sopenharmony_ciint SkTQuad::intersectRay(SkIntersections* i, const SkDLine& line) const { 403cb93a386Sopenharmony_ci return i->intersectRay(fQuad, line); 404cb93a386Sopenharmony_ci} 405cb93a386Sopenharmony_ci 406cb93a386Sopenharmony_cibool SkTQuad::hullIntersects(const SkDConic& conic, bool* isLinear) const { 407cb93a386Sopenharmony_ci return conic.hullIntersects(fQuad, isLinear); 408cb93a386Sopenharmony_ci} 409cb93a386Sopenharmony_ci 410cb93a386Sopenharmony_cibool SkTQuad::hullIntersects(const SkDCubic& cubic, bool* isLinear) const { 411cb93a386Sopenharmony_ci return cubic.hullIntersects(fQuad, isLinear); 412cb93a386Sopenharmony_ci} 413cb93a386Sopenharmony_ci 414cb93a386Sopenharmony_civoid SkTQuad::setBounds(SkDRect* rect) const { 415cb93a386Sopenharmony_ci rect->setBounds(fQuad); 416cb93a386Sopenharmony_ci} 417