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/SkPathOpsCubic.h" 9cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsCurve.h" 10cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsLine.h" 11cb93a386Sopenharmony_ci 12cb93a386Sopenharmony_ci/* 13cb93a386Sopenharmony_ciFind the interection of a line and cubic by solving for valid t values. 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_ciAnalogous to line-quadratic intersection, solve line-cubic intersection by 16cb93a386Sopenharmony_cirepresenting the cubic as: 17cb93a386Sopenharmony_ci x = a(1-t)^3 + 2b(1-t)^2t + c(1-t)t^2 + dt^3 18cb93a386Sopenharmony_ci y = e(1-t)^3 + 2f(1-t)^2t + g(1-t)t^2 + ht^3 19cb93a386Sopenharmony_ciand the line as: 20cb93a386Sopenharmony_ci y = i*x + j (if the line is more horizontal) 21cb93a386Sopenharmony_cior: 22cb93a386Sopenharmony_ci x = i*y + j (if the line is more vertical) 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_ciThen using Mathematica, solve for the values of t where the cubic intersects the 25cb93a386Sopenharmony_ciline: 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_ci (in) Resultant[ 28cb93a386Sopenharmony_ci a*(1 - t)^3 + 3*b*(1 - t)^2*t + 3*c*(1 - t)*t^2 + d*t^3 - x, 29cb93a386Sopenharmony_ci e*(1 - t)^3 + 3*f*(1 - t)^2*t + 3*g*(1 - t)*t^2 + h*t^3 - i*x - j, x] 30cb93a386Sopenharmony_ci (out) -e + j + 31cb93a386Sopenharmony_ci 3 e t - 3 f t - 32cb93a386Sopenharmony_ci 3 e t^2 + 6 f t^2 - 3 g t^2 + 33cb93a386Sopenharmony_ci e t^3 - 3 f t^3 + 3 g t^3 - h t^3 + 34cb93a386Sopenharmony_ci i ( a - 35cb93a386Sopenharmony_ci 3 a t + 3 b t + 36cb93a386Sopenharmony_ci 3 a t^2 - 6 b t^2 + 3 c t^2 - 37cb93a386Sopenharmony_ci a t^3 + 3 b t^3 - 3 c t^3 + d t^3 ) 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ciif i goes to infinity, we can rewrite the line in terms of x. Mathematica: 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci (in) Resultant[ 42cb93a386Sopenharmony_ci a*(1 - t)^3 + 3*b*(1 - t)^2*t + 3*c*(1 - t)*t^2 + d*t^3 - i*y - j, 43cb93a386Sopenharmony_ci e*(1 - t)^3 + 3*f*(1 - t)^2*t + 3*g*(1 - t)*t^2 + h*t^3 - y, y] 44cb93a386Sopenharmony_ci (out) a - j - 45cb93a386Sopenharmony_ci 3 a t + 3 b t + 46cb93a386Sopenharmony_ci 3 a t^2 - 6 b t^2 + 3 c t^2 - 47cb93a386Sopenharmony_ci a t^3 + 3 b t^3 - 3 c t^3 + d t^3 - 48cb93a386Sopenharmony_ci i ( e - 49cb93a386Sopenharmony_ci 3 e t + 3 f t + 50cb93a386Sopenharmony_ci 3 e t^2 - 6 f t^2 + 3 g t^2 - 51cb93a386Sopenharmony_ci e t^3 + 3 f t^3 - 3 g t^3 + h t^3 ) 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_ciSolving this with Mathematica produces an expression with hundreds of terms; 54cb93a386Sopenharmony_ciinstead, use Numeric Solutions recipe to solve the cubic. 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ciThe near-horizontal case, in terms of: Ax^3 + Bx^2 + Cx + D == 0 57cb93a386Sopenharmony_ci A = (-(-e + 3*f - 3*g + h) + i*(-a + 3*b - 3*c + d) ) 58cb93a386Sopenharmony_ci B = 3*(-( e - 2*f + g ) + i*( a - 2*b + c ) ) 59cb93a386Sopenharmony_ci C = 3*(-(-e + f ) + i*(-a + b ) ) 60cb93a386Sopenharmony_ci D = (-( e ) + i*( a ) + j ) 61cb93a386Sopenharmony_ci 62cb93a386Sopenharmony_ciThe near-vertical case, in terms of: Ax^3 + Bx^2 + Cx + D == 0 63cb93a386Sopenharmony_ci A = ( (-a + 3*b - 3*c + d) - i*(-e + 3*f - 3*g + h) ) 64cb93a386Sopenharmony_ci B = 3*( ( a - 2*b + c ) - i*( e - 2*f + g ) ) 65cb93a386Sopenharmony_ci C = 3*( (-a + b ) - i*(-e + f ) ) 66cb93a386Sopenharmony_ci D = ( ( a ) - i*( e ) - j ) 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_ciFor horizontal lines: 69cb93a386Sopenharmony_ci(in) Resultant[ 70cb93a386Sopenharmony_ci a*(1 - t)^3 + 3*b*(1 - t)^2*t + 3*c*(1 - t)*t^2 + d*t^3 - j, 71cb93a386Sopenharmony_ci e*(1 - t)^3 + 3*f*(1 - t)^2*t + 3*g*(1 - t)*t^2 + h*t^3 - y, y] 72cb93a386Sopenharmony_ci(out) e - j - 73cb93a386Sopenharmony_ci 3 e t + 3 f t + 74cb93a386Sopenharmony_ci 3 e t^2 - 6 f t^2 + 3 g t^2 - 75cb93a386Sopenharmony_ci e t^3 + 3 f t^3 - 3 g t^3 + h t^3 76cb93a386Sopenharmony_ci */ 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_ciclass LineCubicIntersections { 79cb93a386Sopenharmony_cipublic: 80cb93a386Sopenharmony_ci enum PinTPoint { 81cb93a386Sopenharmony_ci kPointUninitialized, 82cb93a386Sopenharmony_ci kPointInitialized 83cb93a386Sopenharmony_ci }; 84cb93a386Sopenharmony_ci 85cb93a386Sopenharmony_ci LineCubicIntersections(const SkDCubic& c, const SkDLine& l, SkIntersections* i) 86cb93a386Sopenharmony_ci : fCubic(c) 87cb93a386Sopenharmony_ci , fLine(l) 88cb93a386Sopenharmony_ci , fIntersections(i) 89cb93a386Sopenharmony_ci , fAllowNear(true) { 90cb93a386Sopenharmony_ci i->setMax(4); 91cb93a386Sopenharmony_ci } 92cb93a386Sopenharmony_ci 93cb93a386Sopenharmony_ci void allowNear(bool allow) { 94cb93a386Sopenharmony_ci fAllowNear = allow; 95cb93a386Sopenharmony_ci } 96cb93a386Sopenharmony_ci 97cb93a386Sopenharmony_ci void checkCoincident() { 98cb93a386Sopenharmony_ci int last = fIntersections->used() - 1; 99cb93a386Sopenharmony_ci for (int index = 0; index < last; ) { 100cb93a386Sopenharmony_ci double cubicMidT = ((*fIntersections)[0][index] + (*fIntersections)[0][index + 1]) / 2; 101cb93a386Sopenharmony_ci SkDPoint cubicMidPt = fCubic.ptAtT(cubicMidT); 102cb93a386Sopenharmony_ci double t = fLine.nearPoint(cubicMidPt, nullptr); 103cb93a386Sopenharmony_ci if (t < 0) { 104cb93a386Sopenharmony_ci ++index; 105cb93a386Sopenharmony_ci continue; 106cb93a386Sopenharmony_ci } 107cb93a386Sopenharmony_ci if (fIntersections->isCoincident(index)) { 108cb93a386Sopenharmony_ci fIntersections->removeOne(index); 109cb93a386Sopenharmony_ci --last; 110cb93a386Sopenharmony_ci } else if (fIntersections->isCoincident(index + 1)) { 111cb93a386Sopenharmony_ci fIntersections->removeOne(index + 1); 112cb93a386Sopenharmony_ci --last; 113cb93a386Sopenharmony_ci } else { 114cb93a386Sopenharmony_ci fIntersections->setCoincident(index++); 115cb93a386Sopenharmony_ci } 116cb93a386Sopenharmony_ci fIntersections->setCoincident(index); 117cb93a386Sopenharmony_ci } 118cb93a386Sopenharmony_ci } 119cb93a386Sopenharmony_ci 120cb93a386Sopenharmony_ci // see parallel routine in line quadratic intersections 121cb93a386Sopenharmony_ci int intersectRay(double roots[3]) { 122cb93a386Sopenharmony_ci double adj = fLine[1].fX - fLine[0].fX; 123cb93a386Sopenharmony_ci double opp = fLine[1].fY - fLine[0].fY; 124cb93a386Sopenharmony_ci SkDCubic c; 125cb93a386Sopenharmony_ci SkDEBUGCODE(c.fDebugGlobalState = fIntersections->globalState()); 126cb93a386Sopenharmony_ci for (int n = 0; n < 4; ++n) { 127cb93a386Sopenharmony_ci c[n].fX = (fCubic[n].fY - fLine[0].fY) * adj - (fCubic[n].fX - fLine[0].fX) * opp; 128cb93a386Sopenharmony_ci } 129cb93a386Sopenharmony_ci double A, B, C, D; 130cb93a386Sopenharmony_ci SkDCubic::Coefficients(&c[0].fX, &A, &B, &C, &D); 131cb93a386Sopenharmony_ci int count = SkDCubic::RootsValidT(A, B, C, D, roots); 132cb93a386Sopenharmony_ci for (int index = 0; index < count; ++index) { 133cb93a386Sopenharmony_ci SkDPoint calcPt = c.ptAtT(roots[index]); 134cb93a386Sopenharmony_ci if (!approximately_zero(calcPt.fX)) { 135cb93a386Sopenharmony_ci for (int n = 0; n < 4; ++n) { 136cb93a386Sopenharmony_ci c[n].fY = (fCubic[n].fY - fLine[0].fY) * opp 137cb93a386Sopenharmony_ci + (fCubic[n].fX - fLine[0].fX) * adj; 138cb93a386Sopenharmony_ci } 139cb93a386Sopenharmony_ci double extremeTs[6]; 140cb93a386Sopenharmony_ci int extrema = SkDCubic::FindExtrema(&c[0].fX, extremeTs); 141cb93a386Sopenharmony_ci count = c.searchRoots(extremeTs, extrema, 0, SkDCubic::kXAxis, roots); 142cb93a386Sopenharmony_ci break; 143cb93a386Sopenharmony_ci } 144cb93a386Sopenharmony_ci } 145cb93a386Sopenharmony_ci return count; 146cb93a386Sopenharmony_ci } 147cb93a386Sopenharmony_ci 148cb93a386Sopenharmony_ci int intersect() { 149cb93a386Sopenharmony_ci addExactEndPoints(); 150cb93a386Sopenharmony_ci if (fAllowNear) { 151cb93a386Sopenharmony_ci addNearEndPoints(); 152cb93a386Sopenharmony_ci } 153cb93a386Sopenharmony_ci double rootVals[3]; 154cb93a386Sopenharmony_ci int roots = intersectRay(rootVals); 155cb93a386Sopenharmony_ci for (int index = 0; index < roots; ++index) { 156cb93a386Sopenharmony_ci double cubicT = rootVals[index]; 157cb93a386Sopenharmony_ci double lineT = findLineT(cubicT); 158cb93a386Sopenharmony_ci SkDPoint pt; 159cb93a386Sopenharmony_ci if (pinTs(&cubicT, &lineT, &pt, kPointUninitialized) && uniqueAnswer(cubicT, pt)) { 160cb93a386Sopenharmony_ci fIntersections->insert(cubicT, lineT, pt); 161cb93a386Sopenharmony_ci } 162cb93a386Sopenharmony_ci } 163cb93a386Sopenharmony_ci checkCoincident(); 164cb93a386Sopenharmony_ci return fIntersections->used(); 165cb93a386Sopenharmony_ci } 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_ci static int HorizontalIntersect(const SkDCubic& c, double axisIntercept, double roots[3]) { 168cb93a386Sopenharmony_ci double A, B, C, D; 169cb93a386Sopenharmony_ci SkDCubic::Coefficients(&c[0].fY, &A, &B, &C, &D); 170cb93a386Sopenharmony_ci D -= axisIntercept; 171cb93a386Sopenharmony_ci int count = SkDCubic::RootsValidT(A, B, C, D, roots); 172cb93a386Sopenharmony_ci for (int index = 0; index < count; ++index) { 173cb93a386Sopenharmony_ci SkDPoint calcPt = c.ptAtT(roots[index]); 174cb93a386Sopenharmony_ci if (!approximately_equal(calcPt.fY, axisIntercept)) { 175cb93a386Sopenharmony_ci double extremeTs[6]; 176cb93a386Sopenharmony_ci int extrema = SkDCubic::FindExtrema(&c[0].fY, extremeTs); 177cb93a386Sopenharmony_ci count = c.searchRoots(extremeTs, extrema, axisIntercept, SkDCubic::kYAxis, roots); 178cb93a386Sopenharmony_ci break; 179cb93a386Sopenharmony_ci } 180cb93a386Sopenharmony_ci } 181cb93a386Sopenharmony_ci return count; 182cb93a386Sopenharmony_ci } 183cb93a386Sopenharmony_ci 184cb93a386Sopenharmony_ci int horizontalIntersect(double axisIntercept, double left, double right, bool flipped) { 185cb93a386Sopenharmony_ci addExactHorizontalEndPoints(left, right, axisIntercept); 186cb93a386Sopenharmony_ci if (fAllowNear) { 187cb93a386Sopenharmony_ci addNearHorizontalEndPoints(left, right, axisIntercept); 188cb93a386Sopenharmony_ci } 189cb93a386Sopenharmony_ci double roots[3]; 190cb93a386Sopenharmony_ci int count = HorizontalIntersect(fCubic, axisIntercept, roots); 191cb93a386Sopenharmony_ci for (int index = 0; index < count; ++index) { 192cb93a386Sopenharmony_ci double cubicT = roots[index]; 193cb93a386Sopenharmony_ci SkDPoint pt = { fCubic.ptAtT(cubicT).fX, axisIntercept }; 194cb93a386Sopenharmony_ci double lineT = (pt.fX - left) / (right - left); 195cb93a386Sopenharmony_ci if (pinTs(&cubicT, &lineT, &pt, kPointInitialized) && uniqueAnswer(cubicT, pt)) { 196cb93a386Sopenharmony_ci fIntersections->insert(cubicT, lineT, pt); 197cb93a386Sopenharmony_ci } 198cb93a386Sopenharmony_ci } 199cb93a386Sopenharmony_ci if (flipped) { 200cb93a386Sopenharmony_ci fIntersections->flip(); 201cb93a386Sopenharmony_ci } 202cb93a386Sopenharmony_ci checkCoincident(); 203cb93a386Sopenharmony_ci return fIntersections->used(); 204cb93a386Sopenharmony_ci } 205cb93a386Sopenharmony_ci 206cb93a386Sopenharmony_ci bool uniqueAnswer(double cubicT, const SkDPoint& pt) { 207cb93a386Sopenharmony_ci for (int inner = 0; inner < fIntersections->used(); ++inner) { 208cb93a386Sopenharmony_ci if (fIntersections->pt(inner) != pt) { 209cb93a386Sopenharmony_ci continue; 210cb93a386Sopenharmony_ci } 211cb93a386Sopenharmony_ci double existingCubicT = (*fIntersections)[0][inner]; 212cb93a386Sopenharmony_ci if (cubicT == existingCubicT) { 213cb93a386Sopenharmony_ci return false; 214cb93a386Sopenharmony_ci } 215cb93a386Sopenharmony_ci // check if midway on cubic is also same point. If so, discard this 216cb93a386Sopenharmony_ci double cubicMidT = (existingCubicT + cubicT) / 2; 217cb93a386Sopenharmony_ci SkDPoint cubicMidPt = fCubic.ptAtT(cubicMidT); 218cb93a386Sopenharmony_ci if (cubicMidPt.approximatelyEqual(pt)) { 219cb93a386Sopenharmony_ci return false; 220cb93a386Sopenharmony_ci } 221cb93a386Sopenharmony_ci } 222cb93a386Sopenharmony_ci#if ONE_OFF_DEBUG 223cb93a386Sopenharmony_ci SkDPoint cPt = fCubic.ptAtT(cubicT); 224cb93a386Sopenharmony_ci SkDebugf("%s pt=(%1.9g,%1.9g) cPt=(%1.9g,%1.9g)\n", __FUNCTION__, pt.fX, pt.fY, 225cb93a386Sopenharmony_ci cPt.fX, cPt.fY); 226cb93a386Sopenharmony_ci#endif 227cb93a386Sopenharmony_ci return true; 228cb93a386Sopenharmony_ci } 229cb93a386Sopenharmony_ci 230cb93a386Sopenharmony_ci static int VerticalIntersect(const SkDCubic& c, double axisIntercept, double roots[3]) { 231cb93a386Sopenharmony_ci double A, B, C, D; 232cb93a386Sopenharmony_ci SkDCubic::Coefficients(&c[0].fX, &A, &B, &C, &D); 233cb93a386Sopenharmony_ci D -= axisIntercept; 234cb93a386Sopenharmony_ci int count = SkDCubic::RootsValidT(A, B, C, D, roots); 235cb93a386Sopenharmony_ci for (int index = 0; index < count; ++index) { 236cb93a386Sopenharmony_ci SkDPoint calcPt = c.ptAtT(roots[index]); 237cb93a386Sopenharmony_ci if (!approximately_equal(calcPt.fX, axisIntercept)) { 238cb93a386Sopenharmony_ci double extremeTs[6]; 239cb93a386Sopenharmony_ci int extrema = SkDCubic::FindExtrema(&c[0].fX, extremeTs); 240cb93a386Sopenharmony_ci count = c.searchRoots(extremeTs, extrema, axisIntercept, SkDCubic::kXAxis, roots); 241cb93a386Sopenharmony_ci break; 242cb93a386Sopenharmony_ci } 243cb93a386Sopenharmony_ci } 244cb93a386Sopenharmony_ci return count; 245cb93a386Sopenharmony_ci } 246cb93a386Sopenharmony_ci 247cb93a386Sopenharmony_ci int verticalIntersect(double axisIntercept, double top, double bottom, bool flipped) { 248cb93a386Sopenharmony_ci addExactVerticalEndPoints(top, bottom, axisIntercept); 249cb93a386Sopenharmony_ci if (fAllowNear) { 250cb93a386Sopenharmony_ci addNearVerticalEndPoints(top, bottom, axisIntercept); 251cb93a386Sopenharmony_ci } 252cb93a386Sopenharmony_ci double roots[3]; 253cb93a386Sopenharmony_ci int count = VerticalIntersect(fCubic, axisIntercept, roots); 254cb93a386Sopenharmony_ci for (int index = 0; index < count; ++index) { 255cb93a386Sopenharmony_ci double cubicT = roots[index]; 256cb93a386Sopenharmony_ci SkDPoint pt = { axisIntercept, fCubic.ptAtT(cubicT).fY }; 257cb93a386Sopenharmony_ci double lineT = (pt.fY - top) / (bottom - top); 258cb93a386Sopenharmony_ci if (pinTs(&cubicT, &lineT, &pt, kPointInitialized) && uniqueAnswer(cubicT, pt)) { 259cb93a386Sopenharmony_ci fIntersections->insert(cubicT, lineT, pt); 260cb93a386Sopenharmony_ci } 261cb93a386Sopenharmony_ci } 262cb93a386Sopenharmony_ci if (flipped) { 263cb93a386Sopenharmony_ci fIntersections->flip(); 264cb93a386Sopenharmony_ci } 265cb93a386Sopenharmony_ci checkCoincident(); 266cb93a386Sopenharmony_ci return fIntersections->used(); 267cb93a386Sopenharmony_ci } 268cb93a386Sopenharmony_ci 269cb93a386Sopenharmony_ci protected: 270cb93a386Sopenharmony_ci 271cb93a386Sopenharmony_ci void addExactEndPoints() { 272cb93a386Sopenharmony_ci for (int cIndex = 0; cIndex < 4; cIndex += 3) { 273cb93a386Sopenharmony_ci double lineT = fLine.exactPoint(fCubic[cIndex]); 274cb93a386Sopenharmony_ci if (lineT < 0) { 275cb93a386Sopenharmony_ci continue; 276cb93a386Sopenharmony_ci } 277cb93a386Sopenharmony_ci double cubicT = (double) (cIndex >> 1); 278cb93a386Sopenharmony_ci fIntersections->insert(cubicT, lineT, fCubic[cIndex]); 279cb93a386Sopenharmony_ci } 280cb93a386Sopenharmony_ci } 281cb93a386Sopenharmony_ci 282cb93a386Sopenharmony_ci /* Note that this does not look for endpoints of the line that are near the cubic. 283cb93a386Sopenharmony_ci These points are found later when check ends looks for missing points */ 284cb93a386Sopenharmony_ci void addNearEndPoints() { 285cb93a386Sopenharmony_ci for (int cIndex = 0; cIndex < 4; cIndex += 3) { 286cb93a386Sopenharmony_ci double cubicT = (double) (cIndex >> 1); 287cb93a386Sopenharmony_ci if (fIntersections->hasT(cubicT)) { 288cb93a386Sopenharmony_ci continue; 289cb93a386Sopenharmony_ci } 290cb93a386Sopenharmony_ci double lineT = fLine.nearPoint(fCubic[cIndex], nullptr); 291cb93a386Sopenharmony_ci if (lineT < 0) { 292cb93a386Sopenharmony_ci continue; 293cb93a386Sopenharmony_ci } 294cb93a386Sopenharmony_ci fIntersections->insert(cubicT, lineT, fCubic[cIndex]); 295cb93a386Sopenharmony_ci } 296cb93a386Sopenharmony_ci this->addLineNearEndPoints(); 297cb93a386Sopenharmony_ci } 298cb93a386Sopenharmony_ci 299cb93a386Sopenharmony_ci void addLineNearEndPoints() { 300cb93a386Sopenharmony_ci for (int lIndex = 0; lIndex < 2; ++lIndex) { 301cb93a386Sopenharmony_ci double lineT = (double) lIndex; 302cb93a386Sopenharmony_ci if (fIntersections->hasOppT(lineT)) { 303cb93a386Sopenharmony_ci continue; 304cb93a386Sopenharmony_ci } 305cb93a386Sopenharmony_ci double cubicT = ((SkDCurve*) &fCubic)->nearPoint(SkPath::kCubic_Verb, 306cb93a386Sopenharmony_ci fLine[lIndex], fLine[!lIndex]); 307cb93a386Sopenharmony_ci if (cubicT < 0) { 308cb93a386Sopenharmony_ci continue; 309cb93a386Sopenharmony_ci } 310cb93a386Sopenharmony_ci fIntersections->insert(cubicT, lineT, fLine[lIndex]); 311cb93a386Sopenharmony_ci } 312cb93a386Sopenharmony_ci } 313cb93a386Sopenharmony_ci 314cb93a386Sopenharmony_ci void addExactHorizontalEndPoints(double left, double right, double y) { 315cb93a386Sopenharmony_ci for (int cIndex = 0; cIndex < 4; cIndex += 3) { 316cb93a386Sopenharmony_ci double lineT = SkDLine::ExactPointH(fCubic[cIndex], left, right, y); 317cb93a386Sopenharmony_ci if (lineT < 0) { 318cb93a386Sopenharmony_ci continue; 319cb93a386Sopenharmony_ci } 320cb93a386Sopenharmony_ci double cubicT = (double) (cIndex >> 1); 321cb93a386Sopenharmony_ci fIntersections->insert(cubicT, lineT, fCubic[cIndex]); 322cb93a386Sopenharmony_ci } 323cb93a386Sopenharmony_ci } 324cb93a386Sopenharmony_ci 325cb93a386Sopenharmony_ci void addNearHorizontalEndPoints(double left, double right, double y) { 326cb93a386Sopenharmony_ci for (int cIndex = 0; cIndex < 4; cIndex += 3) { 327cb93a386Sopenharmony_ci double cubicT = (double) (cIndex >> 1); 328cb93a386Sopenharmony_ci if (fIntersections->hasT(cubicT)) { 329cb93a386Sopenharmony_ci continue; 330cb93a386Sopenharmony_ci } 331cb93a386Sopenharmony_ci double lineT = SkDLine::NearPointH(fCubic[cIndex], left, right, y); 332cb93a386Sopenharmony_ci if (lineT < 0) { 333cb93a386Sopenharmony_ci continue; 334cb93a386Sopenharmony_ci } 335cb93a386Sopenharmony_ci fIntersections->insert(cubicT, lineT, fCubic[cIndex]); 336cb93a386Sopenharmony_ci } 337cb93a386Sopenharmony_ci this->addLineNearEndPoints(); 338cb93a386Sopenharmony_ci } 339cb93a386Sopenharmony_ci 340cb93a386Sopenharmony_ci void addExactVerticalEndPoints(double top, double bottom, double x) { 341cb93a386Sopenharmony_ci for (int cIndex = 0; cIndex < 4; cIndex += 3) { 342cb93a386Sopenharmony_ci double lineT = SkDLine::ExactPointV(fCubic[cIndex], top, bottom, x); 343cb93a386Sopenharmony_ci if (lineT < 0) { 344cb93a386Sopenharmony_ci continue; 345cb93a386Sopenharmony_ci } 346cb93a386Sopenharmony_ci double cubicT = (double) (cIndex >> 1); 347cb93a386Sopenharmony_ci fIntersections->insert(cubicT, lineT, fCubic[cIndex]); 348cb93a386Sopenharmony_ci } 349cb93a386Sopenharmony_ci } 350cb93a386Sopenharmony_ci 351cb93a386Sopenharmony_ci void addNearVerticalEndPoints(double top, double bottom, double x) { 352cb93a386Sopenharmony_ci for (int cIndex = 0; cIndex < 4; cIndex += 3) { 353cb93a386Sopenharmony_ci double cubicT = (double) (cIndex >> 1); 354cb93a386Sopenharmony_ci if (fIntersections->hasT(cubicT)) { 355cb93a386Sopenharmony_ci continue; 356cb93a386Sopenharmony_ci } 357cb93a386Sopenharmony_ci double lineT = SkDLine::NearPointV(fCubic[cIndex], top, bottom, x); 358cb93a386Sopenharmony_ci if (lineT < 0) { 359cb93a386Sopenharmony_ci continue; 360cb93a386Sopenharmony_ci } 361cb93a386Sopenharmony_ci fIntersections->insert(cubicT, lineT, fCubic[cIndex]); 362cb93a386Sopenharmony_ci } 363cb93a386Sopenharmony_ci this->addLineNearEndPoints(); 364cb93a386Sopenharmony_ci } 365cb93a386Sopenharmony_ci 366cb93a386Sopenharmony_ci double findLineT(double t) { 367cb93a386Sopenharmony_ci SkDPoint xy = fCubic.ptAtT(t); 368cb93a386Sopenharmony_ci double dx = fLine[1].fX - fLine[0].fX; 369cb93a386Sopenharmony_ci double dy = fLine[1].fY - fLine[0].fY; 370cb93a386Sopenharmony_ci if (fabs(dx) > fabs(dy)) { 371cb93a386Sopenharmony_ci return (xy.fX - fLine[0].fX) / dx; 372cb93a386Sopenharmony_ci } 373cb93a386Sopenharmony_ci return (xy.fY - fLine[0].fY) / dy; 374cb93a386Sopenharmony_ci } 375cb93a386Sopenharmony_ci 376cb93a386Sopenharmony_ci bool pinTs(double* cubicT, double* lineT, SkDPoint* pt, PinTPoint ptSet) { 377cb93a386Sopenharmony_ci if (!approximately_one_or_less(*lineT)) { 378cb93a386Sopenharmony_ci return false; 379cb93a386Sopenharmony_ci } 380cb93a386Sopenharmony_ci if (!approximately_zero_or_more(*lineT)) { 381cb93a386Sopenharmony_ci return false; 382cb93a386Sopenharmony_ci } 383cb93a386Sopenharmony_ci double cT = *cubicT = SkPinT(*cubicT); 384cb93a386Sopenharmony_ci double lT = *lineT = SkPinT(*lineT); 385cb93a386Sopenharmony_ci SkDPoint lPt = fLine.ptAtT(lT); 386cb93a386Sopenharmony_ci SkDPoint cPt = fCubic.ptAtT(cT); 387cb93a386Sopenharmony_ci if (!lPt.roughlyEqual(cPt)) { 388cb93a386Sopenharmony_ci return false; 389cb93a386Sopenharmony_ci } 390cb93a386Sopenharmony_ci // FIXME: if points are roughly equal but not approximately equal, need to do 391cb93a386Sopenharmony_ci // a binary search like quad/quad intersection to find more precise t values 392cb93a386Sopenharmony_ci if (lT == 0 || lT == 1 || (ptSet == kPointUninitialized && cT != 0 && cT != 1)) { 393cb93a386Sopenharmony_ci *pt = lPt; 394cb93a386Sopenharmony_ci } else if (ptSet == kPointUninitialized) { 395cb93a386Sopenharmony_ci *pt = cPt; 396cb93a386Sopenharmony_ci } 397cb93a386Sopenharmony_ci SkPoint gridPt = pt->asSkPoint(); 398cb93a386Sopenharmony_ci if (gridPt == fLine[0].asSkPoint()) { 399cb93a386Sopenharmony_ci *lineT = 0; 400cb93a386Sopenharmony_ci } else if (gridPt == fLine[1].asSkPoint()) { 401cb93a386Sopenharmony_ci *lineT = 1; 402cb93a386Sopenharmony_ci } 403cb93a386Sopenharmony_ci if (gridPt == fCubic[0].asSkPoint() && approximately_equal(*cubicT, 0)) { 404cb93a386Sopenharmony_ci *cubicT = 0; 405cb93a386Sopenharmony_ci } else if (gridPt == fCubic[3].asSkPoint() && approximately_equal(*cubicT, 1)) { 406cb93a386Sopenharmony_ci *cubicT = 1; 407cb93a386Sopenharmony_ci } 408cb93a386Sopenharmony_ci return true; 409cb93a386Sopenharmony_ci } 410cb93a386Sopenharmony_ci 411cb93a386Sopenharmony_ciprivate: 412cb93a386Sopenharmony_ci const SkDCubic& fCubic; 413cb93a386Sopenharmony_ci const SkDLine& fLine; 414cb93a386Sopenharmony_ci SkIntersections* fIntersections; 415cb93a386Sopenharmony_ci bool fAllowNear; 416cb93a386Sopenharmony_ci}; 417cb93a386Sopenharmony_ci 418cb93a386Sopenharmony_ciint SkIntersections::horizontal(const SkDCubic& cubic, double left, double right, double y, 419cb93a386Sopenharmony_ci bool flipped) { 420cb93a386Sopenharmony_ci SkDLine line = {{{ left, y }, { right, y }}}; 421cb93a386Sopenharmony_ci LineCubicIntersections c(cubic, line, this); 422cb93a386Sopenharmony_ci return c.horizontalIntersect(y, left, right, flipped); 423cb93a386Sopenharmony_ci} 424cb93a386Sopenharmony_ci 425cb93a386Sopenharmony_ciint SkIntersections::vertical(const SkDCubic& cubic, double top, double bottom, double x, 426cb93a386Sopenharmony_ci bool flipped) { 427cb93a386Sopenharmony_ci SkDLine line = {{{ x, top }, { x, bottom }}}; 428cb93a386Sopenharmony_ci LineCubicIntersections c(cubic, line, this); 429cb93a386Sopenharmony_ci return c.verticalIntersect(x, top, bottom, flipped); 430cb93a386Sopenharmony_ci} 431cb93a386Sopenharmony_ci 432cb93a386Sopenharmony_ciint SkIntersections::intersect(const SkDCubic& cubic, const SkDLine& line) { 433cb93a386Sopenharmony_ci LineCubicIntersections c(cubic, line, this); 434cb93a386Sopenharmony_ci c.allowNear(fAllowNear); 435cb93a386Sopenharmony_ci return c.intersect(); 436cb93a386Sopenharmony_ci} 437cb93a386Sopenharmony_ci 438cb93a386Sopenharmony_ciint SkIntersections::intersectRay(const SkDCubic& cubic, const SkDLine& line) { 439cb93a386Sopenharmony_ci LineCubicIntersections c(cubic, line, this); 440cb93a386Sopenharmony_ci fUsed = c.intersectRay(fT[0]); 441cb93a386Sopenharmony_ci for (int index = 0; index < fUsed; ++index) { 442cb93a386Sopenharmony_ci fPt[index] = cubic.ptAtT(fT[0][index]); 443cb93a386Sopenharmony_ci } 444cb93a386Sopenharmony_ci return fUsed; 445cb93a386Sopenharmony_ci} 446cb93a386Sopenharmony_ci 447cb93a386Sopenharmony_ci// SkDCubic accessors to Intersection utilities 448cb93a386Sopenharmony_ci 449cb93a386Sopenharmony_ciint SkDCubic::horizontalIntersect(double yIntercept, double roots[3]) const { 450cb93a386Sopenharmony_ci return LineCubicIntersections::HorizontalIntersect(*this, yIntercept, roots); 451cb93a386Sopenharmony_ci} 452cb93a386Sopenharmony_ci 453cb93a386Sopenharmony_ciint SkDCubic::verticalIntersect(double xIntercept, double roots[3]) const { 454cb93a386Sopenharmony_ci return LineCubicIntersections::VerticalIntersect(*this, xIntercept, roots); 455cb93a386Sopenharmony_ci} 456