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