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