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/SkPathOpsCurve.h" 9cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsLine.h" 10cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsQuad.h" 11cb93a386Sopenharmony_ci 12cb93a386Sopenharmony_ci/* 13cb93a386Sopenharmony_ciFind the interection of a line and quadratic by solving for valid t values. 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_ciFrom http://stackoverflow.com/questions/1853637/how-to-find-the-mathematical-function-defining-a-bezier-curve 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ci"A Bezier curve is a parametric function. A quadratic Bezier curve (i.e. three 18cb93a386Sopenharmony_cicontrol points) can be expressed as: F(t) = A(1 - t)^2 + B(1 - t)t + Ct^2 where 19cb93a386Sopenharmony_ciA, B and C are points and t goes from zero to one. 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_ciThis will give you two equations: 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ci x = a(1 - t)^2 + b(1 - t)t + ct^2 24cb93a386Sopenharmony_ci y = d(1 - t)^2 + e(1 - t)t + ft^2 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ciIf you add for instance the line equation (y = kx + m) to that, you'll end up 27cb93a386Sopenharmony_ciwith three equations and three unknowns (x, y and t)." 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ciSimilar to above, the quadratic is represented as 30cb93a386Sopenharmony_ci x = a(1-t)^2 + 2b(1-t)t + ct^2 31cb93a386Sopenharmony_ci y = d(1-t)^2 + 2e(1-t)t + ft^2 32cb93a386Sopenharmony_ciand the line as 33cb93a386Sopenharmony_ci y = g*x + h 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ciUsing Mathematica, solve for the values of t where the quadratic intersects the 36cb93a386Sopenharmony_ciline: 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_ci (in) t1 = Resultant[a*(1 - t)^2 + 2*b*(1 - t)*t + c*t^2 - x, 39cb93a386Sopenharmony_ci d*(1 - t)^2 + 2*e*(1 - t)*t + f*t^2 - g*x - h, x] 40cb93a386Sopenharmony_ci (out) -d + h + 2 d t - 2 e t - d t^2 + 2 e t^2 - f t^2 + 41cb93a386Sopenharmony_ci g (a - 2 a t + 2 b t + a t^2 - 2 b t^2 + c t^2) 42cb93a386Sopenharmony_ci (in) Solve[t1 == 0, t] 43cb93a386Sopenharmony_ci (out) { 44cb93a386Sopenharmony_ci {t -> (-2 d + 2 e + 2 a g - 2 b g - 45cb93a386Sopenharmony_ci Sqrt[(2 d - 2 e - 2 a g + 2 b g)^2 - 46cb93a386Sopenharmony_ci 4 (-d + 2 e - f + a g - 2 b g + c g) (-d + a g + h)]) / 47cb93a386Sopenharmony_ci (2 (-d + 2 e - f + a g - 2 b g + c g)) 48cb93a386Sopenharmony_ci }, 49cb93a386Sopenharmony_ci {t -> (-2 d + 2 e + 2 a g - 2 b g + 50cb93a386Sopenharmony_ci Sqrt[(2 d - 2 e - 2 a g + 2 b g)^2 - 51cb93a386Sopenharmony_ci 4 (-d + 2 e - f + a g - 2 b g + c g) (-d + a g + h)]) / 52cb93a386Sopenharmony_ci (2 (-d + 2 e - f + a g - 2 b g + c g)) 53cb93a386Sopenharmony_ci } 54cb93a386Sopenharmony_ci } 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ciUsing the results above (when the line tends towards horizontal) 57cb93a386Sopenharmony_ci A = (-(d - 2*e + f) + g*(a - 2*b + c) ) 58cb93a386Sopenharmony_ci B = 2*( (d - e ) - g*(a - b ) ) 59cb93a386Sopenharmony_ci C = (-(d ) + g*(a ) + h ) 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ciIf g goes to infinity, we can rewrite the line in terms of x. 62cb93a386Sopenharmony_ci x = g'*y + h' 63cb93a386Sopenharmony_ci 64cb93a386Sopenharmony_ciAnd solve accordingly in Mathematica: 65cb93a386Sopenharmony_ci 66cb93a386Sopenharmony_ci (in) t2 = Resultant[a*(1 - t)^2 + 2*b*(1 - t)*t + c*t^2 - g'*y - h', 67cb93a386Sopenharmony_ci d*(1 - t)^2 + 2*e*(1 - t)*t + f*t^2 - y, y] 68cb93a386Sopenharmony_ci (out) a - h' - 2 a t + 2 b t + a t^2 - 2 b t^2 + c t^2 - 69cb93a386Sopenharmony_ci g' (d - 2 d t + 2 e t + d t^2 - 2 e t^2 + f t^2) 70cb93a386Sopenharmony_ci (in) Solve[t2 == 0, t] 71cb93a386Sopenharmony_ci (out) { 72cb93a386Sopenharmony_ci {t -> (2 a - 2 b - 2 d g' + 2 e g' - 73cb93a386Sopenharmony_ci Sqrt[(-2 a + 2 b + 2 d g' - 2 e g')^2 - 74cb93a386Sopenharmony_ci 4 (a - 2 b + c - d g' + 2 e g' - f g') (a - d g' - h')]) / 75cb93a386Sopenharmony_ci (2 (a - 2 b + c - d g' + 2 e g' - f g')) 76cb93a386Sopenharmony_ci }, 77cb93a386Sopenharmony_ci {t -> (2 a - 2 b - 2 d g' + 2 e g' + 78cb93a386Sopenharmony_ci Sqrt[(-2 a + 2 b + 2 d g' - 2 e g')^2 - 79cb93a386Sopenharmony_ci 4 (a - 2 b + c - d g' + 2 e g' - f g') (a - d g' - h')])/ 80cb93a386Sopenharmony_ci (2 (a - 2 b + c - d g' + 2 e g' - f g')) 81cb93a386Sopenharmony_ci } 82cb93a386Sopenharmony_ci } 83cb93a386Sopenharmony_ci 84cb93a386Sopenharmony_ciThus, if the slope of the line tends towards vertical, we use: 85cb93a386Sopenharmony_ci A = ( (a - 2*b + c) - g'*(d - 2*e + f) ) 86cb93a386Sopenharmony_ci B = 2*(-(a - b ) + g'*(d - e ) ) 87cb93a386Sopenharmony_ci C = ( (a ) - g'*(d ) - h' ) 88cb93a386Sopenharmony_ci */ 89cb93a386Sopenharmony_ci 90cb93a386Sopenharmony_ciclass LineQuadraticIntersections { 91cb93a386Sopenharmony_cipublic: 92cb93a386Sopenharmony_ci enum PinTPoint { 93cb93a386Sopenharmony_ci kPointUninitialized, 94cb93a386Sopenharmony_ci kPointInitialized 95cb93a386Sopenharmony_ci }; 96cb93a386Sopenharmony_ci 97cb93a386Sopenharmony_ci LineQuadraticIntersections(const SkDQuad& q, const SkDLine& l, SkIntersections* i) 98cb93a386Sopenharmony_ci : fQuad(q) 99cb93a386Sopenharmony_ci , fLine(&l) 100cb93a386Sopenharmony_ci , fIntersections(i) 101cb93a386Sopenharmony_ci , fAllowNear(true) { 102cb93a386Sopenharmony_ci i->setMax(5); // allow short partial coincidence plus discrete intersections 103cb93a386Sopenharmony_ci } 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ci LineQuadraticIntersections(const SkDQuad& q) 106cb93a386Sopenharmony_ci : fQuad(q) 107cb93a386Sopenharmony_ci SkDEBUGPARAMS(fLine(nullptr)) 108cb93a386Sopenharmony_ci SkDEBUGPARAMS(fIntersections(nullptr)) 109cb93a386Sopenharmony_ci SkDEBUGPARAMS(fAllowNear(false)) { 110cb93a386Sopenharmony_ci } 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci void allowNear(bool allow) { 113cb93a386Sopenharmony_ci fAllowNear = allow; 114cb93a386Sopenharmony_ci } 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_ci void checkCoincident() { 117cb93a386Sopenharmony_ci int last = fIntersections->used() - 1; 118cb93a386Sopenharmony_ci for (int index = 0; index < last; ) { 119cb93a386Sopenharmony_ci double quadMidT = ((*fIntersections)[0][index] + (*fIntersections)[0][index + 1]) / 2; 120cb93a386Sopenharmony_ci SkDPoint quadMidPt = fQuad.ptAtT(quadMidT); 121cb93a386Sopenharmony_ci double t = fLine->nearPoint(quadMidPt, nullptr); 122cb93a386Sopenharmony_ci if (t < 0) { 123cb93a386Sopenharmony_ci ++index; 124cb93a386Sopenharmony_ci continue; 125cb93a386Sopenharmony_ci } 126cb93a386Sopenharmony_ci if (fIntersections->isCoincident(index)) { 127cb93a386Sopenharmony_ci fIntersections->removeOne(index); 128cb93a386Sopenharmony_ci --last; 129cb93a386Sopenharmony_ci } else if (fIntersections->isCoincident(index + 1)) { 130cb93a386Sopenharmony_ci fIntersections->removeOne(index + 1); 131cb93a386Sopenharmony_ci --last; 132cb93a386Sopenharmony_ci } else { 133cb93a386Sopenharmony_ci fIntersections->setCoincident(index++); 134cb93a386Sopenharmony_ci } 135cb93a386Sopenharmony_ci fIntersections->setCoincident(index); 136cb93a386Sopenharmony_ci } 137cb93a386Sopenharmony_ci } 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci int intersectRay(double roots[2]) { 140cb93a386Sopenharmony_ci /* 141cb93a386Sopenharmony_ci solve by rotating line+quad so line is horizontal, then finding the roots 142cb93a386Sopenharmony_ci set up matrix to rotate quad to x-axis 143cb93a386Sopenharmony_ci |cos(a) -sin(a)| 144cb93a386Sopenharmony_ci |sin(a) cos(a)| 145cb93a386Sopenharmony_ci note that cos(a) = A(djacent) / Hypoteneuse 146cb93a386Sopenharmony_ci sin(a) = O(pposite) / Hypoteneuse 147cb93a386Sopenharmony_ci since we are computing Ts, we can ignore hypoteneuse, the scale factor: 148cb93a386Sopenharmony_ci | A -O | 149cb93a386Sopenharmony_ci | O A | 150cb93a386Sopenharmony_ci A = line[1].fX - line[0].fX (adjacent side of the right triangle) 151cb93a386Sopenharmony_ci O = line[1].fY - line[0].fY (opposite side of the right triangle) 152cb93a386Sopenharmony_ci for each of the three points (e.g. n = 0 to 2) 153cb93a386Sopenharmony_ci quad[n].fY' = (quad[n].fY - line[0].fY) * A - (quad[n].fX - line[0].fX) * O 154cb93a386Sopenharmony_ci */ 155cb93a386Sopenharmony_ci double adj = (*fLine)[1].fX - (*fLine)[0].fX; 156cb93a386Sopenharmony_ci double opp = (*fLine)[1].fY - (*fLine)[0].fY; 157cb93a386Sopenharmony_ci double r[3]; 158cb93a386Sopenharmony_ci for (int n = 0; n < 3; ++n) { 159cb93a386Sopenharmony_ci r[n] = (fQuad[n].fY - (*fLine)[0].fY) * adj - (fQuad[n].fX - (*fLine)[0].fX) * opp; 160cb93a386Sopenharmony_ci } 161cb93a386Sopenharmony_ci double A = r[2]; 162cb93a386Sopenharmony_ci double B = r[1]; 163cb93a386Sopenharmony_ci double C = r[0]; 164cb93a386Sopenharmony_ci A += C - 2 * B; // A = a - 2*b + c 165cb93a386Sopenharmony_ci B -= C; // B = -(b - c) 166cb93a386Sopenharmony_ci return SkDQuad::RootsValidT(A, 2 * B, C, roots); 167cb93a386Sopenharmony_ci } 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_ci int intersect() { 170cb93a386Sopenharmony_ci addExactEndPoints(); 171cb93a386Sopenharmony_ci if (fAllowNear) { 172cb93a386Sopenharmony_ci addNearEndPoints(); 173cb93a386Sopenharmony_ci } 174cb93a386Sopenharmony_ci double rootVals[2]; 175cb93a386Sopenharmony_ci int roots = intersectRay(rootVals); 176cb93a386Sopenharmony_ci for (int index = 0; index < roots; ++index) { 177cb93a386Sopenharmony_ci double quadT = rootVals[index]; 178cb93a386Sopenharmony_ci double lineT = findLineT(quadT); 179cb93a386Sopenharmony_ci SkDPoint pt; 180cb93a386Sopenharmony_ci if (pinTs(&quadT, &lineT, &pt, kPointUninitialized) && uniqueAnswer(quadT, pt)) { 181cb93a386Sopenharmony_ci fIntersections->insert(quadT, lineT, pt); 182cb93a386Sopenharmony_ci } 183cb93a386Sopenharmony_ci } 184cb93a386Sopenharmony_ci checkCoincident(); 185cb93a386Sopenharmony_ci return fIntersections->used(); 186cb93a386Sopenharmony_ci } 187cb93a386Sopenharmony_ci 188cb93a386Sopenharmony_ci int horizontalIntersect(double axisIntercept, double roots[2]) { 189cb93a386Sopenharmony_ci double D = fQuad[2].fY; // f 190cb93a386Sopenharmony_ci double E = fQuad[1].fY; // e 191cb93a386Sopenharmony_ci double F = fQuad[0].fY; // d 192cb93a386Sopenharmony_ci D += F - 2 * E; // D = d - 2*e + f 193cb93a386Sopenharmony_ci E -= F; // E = -(d - e) 194cb93a386Sopenharmony_ci F -= axisIntercept; 195cb93a386Sopenharmony_ci return SkDQuad::RootsValidT(D, 2 * E, F, roots); 196cb93a386Sopenharmony_ci } 197cb93a386Sopenharmony_ci 198cb93a386Sopenharmony_ci int horizontalIntersect(double axisIntercept, double left, double right, bool flipped) { 199cb93a386Sopenharmony_ci addExactHorizontalEndPoints(left, right, axisIntercept); 200cb93a386Sopenharmony_ci if (fAllowNear) { 201cb93a386Sopenharmony_ci addNearHorizontalEndPoints(left, right, axisIntercept); 202cb93a386Sopenharmony_ci } 203cb93a386Sopenharmony_ci double rootVals[2]; 204cb93a386Sopenharmony_ci int roots = horizontalIntersect(axisIntercept, rootVals); 205cb93a386Sopenharmony_ci for (int index = 0; index < roots; ++index) { 206cb93a386Sopenharmony_ci double quadT = rootVals[index]; 207cb93a386Sopenharmony_ci SkDPoint pt = fQuad.ptAtT(quadT); 208cb93a386Sopenharmony_ci double lineT = (pt.fX - left) / (right - left); 209cb93a386Sopenharmony_ci if (pinTs(&quadT, &lineT, &pt, kPointInitialized) && uniqueAnswer(quadT, pt)) { 210cb93a386Sopenharmony_ci fIntersections->insert(quadT, lineT, pt); 211cb93a386Sopenharmony_ci } 212cb93a386Sopenharmony_ci } 213cb93a386Sopenharmony_ci if (flipped) { 214cb93a386Sopenharmony_ci fIntersections->flip(); 215cb93a386Sopenharmony_ci } 216cb93a386Sopenharmony_ci checkCoincident(); 217cb93a386Sopenharmony_ci return fIntersections->used(); 218cb93a386Sopenharmony_ci } 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_ci bool uniqueAnswer(double quadT, const SkDPoint& pt) { 221cb93a386Sopenharmony_ci for (int inner = 0; inner < fIntersections->used(); ++inner) { 222cb93a386Sopenharmony_ci if (fIntersections->pt(inner) != pt) { 223cb93a386Sopenharmony_ci continue; 224cb93a386Sopenharmony_ci } 225cb93a386Sopenharmony_ci double existingQuadT = (*fIntersections)[0][inner]; 226cb93a386Sopenharmony_ci if (quadT == existingQuadT) { 227cb93a386Sopenharmony_ci return false; 228cb93a386Sopenharmony_ci } 229cb93a386Sopenharmony_ci // check if midway on quad is also same point. If so, discard this 230cb93a386Sopenharmony_ci double quadMidT = (existingQuadT + quadT) / 2; 231cb93a386Sopenharmony_ci SkDPoint quadMidPt = fQuad.ptAtT(quadMidT); 232cb93a386Sopenharmony_ci if (quadMidPt.approximatelyEqual(pt)) { 233cb93a386Sopenharmony_ci return false; 234cb93a386Sopenharmony_ci } 235cb93a386Sopenharmony_ci } 236cb93a386Sopenharmony_ci#if ONE_OFF_DEBUG 237cb93a386Sopenharmony_ci SkDPoint qPt = fQuad.ptAtT(quadT); 238cb93a386Sopenharmony_ci SkDebugf("%s pt=(%1.9g,%1.9g) cPt=(%1.9g,%1.9g)\n", __FUNCTION__, pt.fX, pt.fY, 239cb93a386Sopenharmony_ci qPt.fX, qPt.fY); 240cb93a386Sopenharmony_ci#endif 241cb93a386Sopenharmony_ci return true; 242cb93a386Sopenharmony_ci } 243cb93a386Sopenharmony_ci 244cb93a386Sopenharmony_ci int verticalIntersect(double axisIntercept, double roots[2]) { 245cb93a386Sopenharmony_ci double D = fQuad[2].fX; // f 246cb93a386Sopenharmony_ci double E = fQuad[1].fX; // e 247cb93a386Sopenharmony_ci double F = fQuad[0].fX; // d 248cb93a386Sopenharmony_ci D += F - 2 * E; // D = d - 2*e + f 249cb93a386Sopenharmony_ci E -= F; // E = -(d - e) 250cb93a386Sopenharmony_ci F -= axisIntercept; 251cb93a386Sopenharmony_ci return SkDQuad::RootsValidT(D, 2 * E, F, roots); 252cb93a386Sopenharmony_ci } 253cb93a386Sopenharmony_ci 254cb93a386Sopenharmony_ci int verticalIntersect(double axisIntercept, double top, double bottom, bool flipped) { 255cb93a386Sopenharmony_ci addExactVerticalEndPoints(top, bottom, axisIntercept); 256cb93a386Sopenharmony_ci if (fAllowNear) { 257cb93a386Sopenharmony_ci addNearVerticalEndPoints(top, bottom, axisIntercept); 258cb93a386Sopenharmony_ci } 259cb93a386Sopenharmony_ci double rootVals[2]; 260cb93a386Sopenharmony_ci int roots = verticalIntersect(axisIntercept, rootVals); 261cb93a386Sopenharmony_ci for (int index = 0; index < roots; ++index) { 262cb93a386Sopenharmony_ci double quadT = rootVals[index]; 263cb93a386Sopenharmony_ci SkDPoint pt = fQuad.ptAtT(quadT); 264cb93a386Sopenharmony_ci double lineT = (pt.fY - top) / (bottom - top); 265cb93a386Sopenharmony_ci if (pinTs(&quadT, &lineT, &pt, kPointInitialized) && uniqueAnswer(quadT, pt)) { 266cb93a386Sopenharmony_ci fIntersections->insert(quadT, lineT, pt); 267cb93a386Sopenharmony_ci } 268cb93a386Sopenharmony_ci } 269cb93a386Sopenharmony_ci if (flipped) { 270cb93a386Sopenharmony_ci fIntersections->flip(); 271cb93a386Sopenharmony_ci } 272cb93a386Sopenharmony_ci checkCoincident(); 273cb93a386Sopenharmony_ci return fIntersections->used(); 274cb93a386Sopenharmony_ci } 275cb93a386Sopenharmony_ci 276cb93a386Sopenharmony_ciprotected: 277cb93a386Sopenharmony_ci // add endpoints first to get zero and one t values exactly 278cb93a386Sopenharmony_ci void addExactEndPoints() { 279cb93a386Sopenharmony_ci for (int qIndex = 0; qIndex < 3; qIndex += 2) { 280cb93a386Sopenharmony_ci double lineT = fLine->exactPoint(fQuad[qIndex]); 281cb93a386Sopenharmony_ci if (lineT < 0) { 282cb93a386Sopenharmony_ci continue; 283cb93a386Sopenharmony_ci } 284cb93a386Sopenharmony_ci double quadT = (double) (qIndex >> 1); 285cb93a386Sopenharmony_ci fIntersections->insert(quadT, lineT, fQuad[qIndex]); 286cb93a386Sopenharmony_ci } 287cb93a386Sopenharmony_ci } 288cb93a386Sopenharmony_ci 289cb93a386Sopenharmony_ci void addNearEndPoints() { 290cb93a386Sopenharmony_ci for (int qIndex = 0; qIndex < 3; qIndex += 2) { 291cb93a386Sopenharmony_ci double quadT = (double) (qIndex >> 1); 292cb93a386Sopenharmony_ci if (fIntersections->hasT(quadT)) { 293cb93a386Sopenharmony_ci continue; 294cb93a386Sopenharmony_ci } 295cb93a386Sopenharmony_ci double lineT = fLine->nearPoint(fQuad[qIndex], nullptr); 296cb93a386Sopenharmony_ci if (lineT < 0) { 297cb93a386Sopenharmony_ci continue; 298cb93a386Sopenharmony_ci } 299cb93a386Sopenharmony_ci fIntersections->insert(quadT, lineT, fQuad[qIndex]); 300cb93a386Sopenharmony_ci } 301cb93a386Sopenharmony_ci this->addLineNearEndPoints(); 302cb93a386Sopenharmony_ci } 303cb93a386Sopenharmony_ci 304cb93a386Sopenharmony_ci void addLineNearEndPoints() { 305cb93a386Sopenharmony_ci for (int lIndex = 0; lIndex < 2; ++lIndex) { 306cb93a386Sopenharmony_ci double lineT = (double) lIndex; 307cb93a386Sopenharmony_ci if (fIntersections->hasOppT(lineT)) { 308cb93a386Sopenharmony_ci continue; 309cb93a386Sopenharmony_ci } 310cb93a386Sopenharmony_ci double quadT = ((SkDCurve*) &fQuad)->nearPoint(SkPath::kQuad_Verb, 311cb93a386Sopenharmony_ci (*fLine)[lIndex], (*fLine)[!lIndex]); 312cb93a386Sopenharmony_ci if (quadT < 0) { 313cb93a386Sopenharmony_ci continue; 314cb93a386Sopenharmony_ci } 315cb93a386Sopenharmony_ci fIntersections->insert(quadT, lineT, (*fLine)[lIndex]); 316cb93a386Sopenharmony_ci } 317cb93a386Sopenharmony_ci } 318cb93a386Sopenharmony_ci 319cb93a386Sopenharmony_ci void addExactHorizontalEndPoints(double left, double right, double y) { 320cb93a386Sopenharmony_ci for (int qIndex = 0; qIndex < 3; qIndex += 2) { 321cb93a386Sopenharmony_ci double lineT = SkDLine::ExactPointH(fQuad[qIndex], left, right, y); 322cb93a386Sopenharmony_ci if (lineT < 0) { 323cb93a386Sopenharmony_ci continue; 324cb93a386Sopenharmony_ci } 325cb93a386Sopenharmony_ci double quadT = (double) (qIndex >> 1); 326cb93a386Sopenharmony_ci fIntersections->insert(quadT, lineT, fQuad[qIndex]); 327cb93a386Sopenharmony_ci } 328cb93a386Sopenharmony_ci } 329cb93a386Sopenharmony_ci 330cb93a386Sopenharmony_ci void addNearHorizontalEndPoints(double left, double right, double y) { 331cb93a386Sopenharmony_ci for (int qIndex = 0; qIndex < 3; qIndex += 2) { 332cb93a386Sopenharmony_ci double quadT = (double) (qIndex >> 1); 333cb93a386Sopenharmony_ci if (fIntersections->hasT(quadT)) { 334cb93a386Sopenharmony_ci continue; 335cb93a386Sopenharmony_ci } 336cb93a386Sopenharmony_ci double lineT = SkDLine::NearPointH(fQuad[qIndex], left, right, y); 337cb93a386Sopenharmony_ci if (lineT < 0) { 338cb93a386Sopenharmony_ci continue; 339cb93a386Sopenharmony_ci } 340cb93a386Sopenharmony_ci fIntersections->insert(quadT, lineT, fQuad[qIndex]); 341cb93a386Sopenharmony_ci } 342cb93a386Sopenharmony_ci this->addLineNearEndPoints(); 343cb93a386Sopenharmony_ci } 344cb93a386Sopenharmony_ci 345cb93a386Sopenharmony_ci void addExactVerticalEndPoints(double top, double bottom, double x) { 346cb93a386Sopenharmony_ci for (int qIndex = 0; qIndex < 3; qIndex += 2) { 347cb93a386Sopenharmony_ci double lineT = SkDLine::ExactPointV(fQuad[qIndex], top, bottom, x); 348cb93a386Sopenharmony_ci if (lineT < 0) { 349cb93a386Sopenharmony_ci continue; 350cb93a386Sopenharmony_ci } 351cb93a386Sopenharmony_ci double quadT = (double) (qIndex >> 1); 352cb93a386Sopenharmony_ci fIntersections->insert(quadT, lineT, fQuad[qIndex]); 353cb93a386Sopenharmony_ci } 354cb93a386Sopenharmony_ci } 355cb93a386Sopenharmony_ci 356cb93a386Sopenharmony_ci void addNearVerticalEndPoints(double top, double bottom, double x) { 357cb93a386Sopenharmony_ci for (int qIndex = 0; qIndex < 3; qIndex += 2) { 358cb93a386Sopenharmony_ci double quadT = (double) (qIndex >> 1); 359cb93a386Sopenharmony_ci if (fIntersections->hasT(quadT)) { 360cb93a386Sopenharmony_ci continue; 361cb93a386Sopenharmony_ci } 362cb93a386Sopenharmony_ci double lineT = SkDLine::NearPointV(fQuad[qIndex], top, bottom, x); 363cb93a386Sopenharmony_ci if (lineT < 0) { 364cb93a386Sopenharmony_ci continue; 365cb93a386Sopenharmony_ci } 366cb93a386Sopenharmony_ci fIntersections->insert(quadT, lineT, fQuad[qIndex]); 367cb93a386Sopenharmony_ci } 368cb93a386Sopenharmony_ci this->addLineNearEndPoints(); 369cb93a386Sopenharmony_ci } 370cb93a386Sopenharmony_ci 371cb93a386Sopenharmony_ci double findLineT(double t) { 372cb93a386Sopenharmony_ci SkDPoint xy = fQuad.ptAtT(t); 373cb93a386Sopenharmony_ci double dx = (*fLine)[1].fX - (*fLine)[0].fX; 374cb93a386Sopenharmony_ci double dy = (*fLine)[1].fY - (*fLine)[0].fY; 375cb93a386Sopenharmony_ci if (fabs(dx) > fabs(dy)) { 376cb93a386Sopenharmony_ci return (xy.fX - (*fLine)[0].fX) / dx; 377cb93a386Sopenharmony_ci } 378cb93a386Sopenharmony_ci return (xy.fY - (*fLine)[0].fY) / dy; 379cb93a386Sopenharmony_ci } 380cb93a386Sopenharmony_ci 381cb93a386Sopenharmony_ci bool pinTs(double* quadT, double* lineT, SkDPoint* pt, PinTPoint ptSet) { 382cb93a386Sopenharmony_ci if (!approximately_one_or_less_double(*lineT)) { 383cb93a386Sopenharmony_ci return false; 384cb93a386Sopenharmony_ci } 385cb93a386Sopenharmony_ci if (!approximately_zero_or_more_double(*lineT)) { 386cb93a386Sopenharmony_ci return false; 387cb93a386Sopenharmony_ci } 388cb93a386Sopenharmony_ci double qT = *quadT = SkPinT(*quadT); 389cb93a386Sopenharmony_ci double lT = *lineT = SkPinT(*lineT); 390cb93a386Sopenharmony_ci if (lT == 0 || lT == 1 || (ptSet == kPointUninitialized && qT != 0 && qT != 1)) { 391cb93a386Sopenharmony_ci *pt = (*fLine).ptAtT(lT); 392cb93a386Sopenharmony_ci } else if (ptSet == kPointUninitialized) { 393cb93a386Sopenharmony_ci *pt = fQuad.ptAtT(qT); 394cb93a386Sopenharmony_ci } 395cb93a386Sopenharmony_ci SkPoint gridPt = pt->asSkPoint(); 396cb93a386Sopenharmony_ci if (SkDPoint::ApproximatelyEqual(gridPt, (*fLine)[0].asSkPoint())) { 397cb93a386Sopenharmony_ci *pt = (*fLine)[0]; 398cb93a386Sopenharmony_ci *lineT = 0; 399cb93a386Sopenharmony_ci } else if (SkDPoint::ApproximatelyEqual(gridPt, (*fLine)[1].asSkPoint())) { 400cb93a386Sopenharmony_ci *pt = (*fLine)[1]; 401cb93a386Sopenharmony_ci *lineT = 1; 402cb93a386Sopenharmony_ci } 403cb93a386Sopenharmony_ci if (fIntersections->used() > 0 && approximately_equal((*fIntersections)[1][0], *lineT)) { 404cb93a386Sopenharmony_ci return false; 405cb93a386Sopenharmony_ci } 406cb93a386Sopenharmony_ci if (gridPt == fQuad[0].asSkPoint()) { 407cb93a386Sopenharmony_ci *pt = fQuad[0]; 408cb93a386Sopenharmony_ci *quadT = 0; 409cb93a386Sopenharmony_ci } else if (gridPt == fQuad[2].asSkPoint()) { 410cb93a386Sopenharmony_ci *pt = fQuad[2]; 411cb93a386Sopenharmony_ci *quadT = 1; 412cb93a386Sopenharmony_ci } 413cb93a386Sopenharmony_ci return true; 414cb93a386Sopenharmony_ci } 415cb93a386Sopenharmony_ci 416cb93a386Sopenharmony_ciprivate: 417cb93a386Sopenharmony_ci const SkDQuad& fQuad; 418cb93a386Sopenharmony_ci const SkDLine* fLine; 419cb93a386Sopenharmony_ci SkIntersections* fIntersections; 420cb93a386Sopenharmony_ci bool fAllowNear; 421cb93a386Sopenharmony_ci}; 422cb93a386Sopenharmony_ci 423cb93a386Sopenharmony_ciint SkIntersections::horizontal(const SkDQuad& quad, double left, double right, double y, 424cb93a386Sopenharmony_ci bool flipped) { 425cb93a386Sopenharmony_ci SkDLine line = {{{ left, y }, { right, y }}}; 426cb93a386Sopenharmony_ci LineQuadraticIntersections q(quad, line, this); 427cb93a386Sopenharmony_ci return q.horizontalIntersect(y, left, right, flipped); 428cb93a386Sopenharmony_ci} 429cb93a386Sopenharmony_ci 430cb93a386Sopenharmony_ciint SkIntersections::vertical(const SkDQuad& quad, double top, double bottom, double x, 431cb93a386Sopenharmony_ci bool flipped) { 432cb93a386Sopenharmony_ci SkDLine line = {{{ x, top }, { x, bottom }}}; 433cb93a386Sopenharmony_ci LineQuadraticIntersections q(quad, line, this); 434cb93a386Sopenharmony_ci return q.verticalIntersect(x, top, bottom, flipped); 435cb93a386Sopenharmony_ci} 436cb93a386Sopenharmony_ci 437cb93a386Sopenharmony_ciint SkIntersections::intersect(const SkDQuad& quad, const SkDLine& line) { 438cb93a386Sopenharmony_ci LineQuadraticIntersections q(quad, line, this); 439cb93a386Sopenharmony_ci q.allowNear(fAllowNear); 440cb93a386Sopenharmony_ci return q.intersect(); 441cb93a386Sopenharmony_ci} 442cb93a386Sopenharmony_ci 443cb93a386Sopenharmony_ciint SkIntersections::intersectRay(const SkDQuad& quad, const SkDLine& line) { 444cb93a386Sopenharmony_ci LineQuadraticIntersections q(quad, line, this); 445cb93a386Sopenharmony_ci fUsed = q.intersectRay(fT[0]); 446cb93a386Sopenharmony_ci for (int index = 0; index < fUsed; ++index) { 447cb93a386Sopenharmony_ci fPt[index] = quad.ptAtT(fT[0][index]); 448cb93a386Sopenharmony_ci } 449cb93a386Sopenharmony_ci return fUsed; 450cb93a386Sopenharmony_ci} 451cb93a386Sopenharmony_ci 452cb93a386Sopenharmony_ciint SkIntersections::HorizontalIntercept(const SkDQuad& quad, SkScalar y, double* roots) { 453cb93a386Sopenharmony_ci LineQuadraticIntersections q(quad); 454cb93a386Sopenharmony_ci return q.horizontalIntersect(y, roots); 455cb93a386Sopenharmony_ci} 456cb93a386Sopenharmony_ci 457cb93a386Sopenharmony_ciint SkIntersections::VerticalIntercept(const SkDQuad& quad, SkScalar x, double* roots) { 458cb93a386Sopenharmony_ci LineQuadraticIntersections q(quad); 459cb93a386Sopenharmony_ci return q.verticalIntersect(x, roots); 460cb93a386Sopenharmony_ci} 461cb93a386Sopenharmony_ci 462cb93a386Sopenharmony_ci// SkDQuad accessors to Intersection utilities 463cb93a386Sopenharmony_ci 464cb93a386Sopenharmony_ciint SkDQuad::horizontalIntersect(double yIntercept, double roots[2]) const { 465cb93a386Sopenharmony_ci return SkIntersections::HorizontalIntercept(*this, yIntercept, roots); 466cb93a386Sopenharmony_ci} 467cb93a386Sopenharmony_ci 468cb93a386Sopenharmony_ciint SkDQuad::verticalIntersect(double xIntercept, double roots[2]) const { 469cb93a386Sopenharmony_ci return SkIntersections::VerticalIntercept(*this, xIntercept, roots); 470cb93a386Sopenharmony_ci} 471