| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 #include "SkIntersections.h" | 7 #include "SkIntersections.h" |
| 8 #include "SkPathOpsLine.h" | 8 #include "SkPathOpsLine.h" |
| 9 #include "SkPathOpsQuad.h" | 9 #include "SkPathOpsQuad.h" |
| 10 | 10 |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 85 B = 2*(-(a - b ) + g'*(d - e ) ) | 85 B = 2*(-(a - b ) + g'*(d - e ) ) |
| 86 C = ( (a ) - g'*(d ) - h' ) | 86 C = ( (a ) - g'*(d ) - h' ) |
| 87 */ | 87 */ |
| 88 | 88 |
| 89 | 89 |
| 90 class LineQuadraticIntersections { | 90 class LineQuadraticIntersections { |
| 91 public: | 91 public: |
| 92 LineQuadraticIntersections(const SkDQuad& q, const SkDLine& l, SkIntersectio
ns* i) | 92 LineQuadraticIntersections(const SkDQuad& q, const SkDLine& l, SkIntersectio
ns* i) |
| 93 : quad(q) | 93 : quad(q) |
| 94 , line(l) | 94 , line(l) |
| 95 , intersections(i) { | 95 , intersections(i) |
| 96 , fAllowNear(true) { |
| 97 } |
| 98 |
| 99 void allowNear(bool allow) { |
| 100 fAllowNear = allow; |
| 96 } | 101 } |
| 97 | 102 |
| 98 int intersectRay(double roots[2]) { | 103 int intersectRay(double roots[2]) { |
| 99 /* | 104 /* |
| 100 solve by rotating line+quad so line is horizontal, then finding the root
s | 105 solve by rotating line+quad so line is horizontal, then finding the root
s |
| 101 set up matrix to rotate quad to x-axis | 106 set up matrix to rotate quad to x-axis |
| 102 |cos(a) -sin(a)| | 107 |cos(a) -sin(a)| |
| 103 |sin(a) cos(a)| | 108 |sin(a) cos(a)| |
| 104 note that cos(a) = A(djacent) / Hypoteneuse | 109 note that cos(a) = A(djacent) / Hypoteneuse |
| 105 sin(a) = O(pposite) / Hypoteneuse | 110 sin(a) = O(pposite) / Hypoteneuse |
| (...skipping 13 matching lines...) Expand all Loading... |
| 119 } | 124 } |
| 120 double A = r[2]; | 125 double A = r[2]; |
| 121 double B = r[1]; | 126 double B = r[1]; |
| 122 double C = r[0]; | 127 double C = r[0]; |
| 123 A += C - 2 * B; // A = a - 2*b + c | 128 A += C - 2 * B; // A = a - 2*b + c |
| 124 B -= C; // B = -(b - c) | 129 B -= C; // B = -(b - c) |
| 125 return SkDQuad::RootsValidT(A, 2 * B, C, roots); | 130 return SkDQuad::RootsValidT(A, 2 * B, C, roots); |
| 126 } | 131 } |
| 127 | 132 |
| 128 int intersect() { | 133 int intersect() { |
| 129 addEndPoints(); | 134 addExactEndPoints(); |
| 130 double rootVals[2]; | 135 double rootVals[2]; |
| 131 int roots = intersectRay(rootVals); | 136 int roots = intersectRay(rootVals); |
| 132 for (int index = 0; index < roots; ++index) { | 137 for (int index = 0; index < roots; ++index) { |
| 133 double quadT = rootVals[index]; | 138 double quadT = rootVals[index]; |
| 134 double lineT = findLineT(quadT); | 139 double lineT = findLineT(quadT); |
| 135 if (PinTs(&quadT, &lineT)) { | 140 if (PinTs(&quadT, &lineT)) { |
| 136 SkDPoint pt = line.xyAtT(lineT); | 141 SkDPoint pt = line.xyAtT(lineT); |
| 137 intersections->insert(quadT, lineT, pt); | 142 intersections->insert(quadT, lineT, pt); |
| 138 } | 143 } |
| 139 } | 144 } |
| 145 if (fAllowNear) { |
| 146 addNearEndPoints(); |
| 147 } |
| 140 return intersections->used(); | 148 return intersections->used(); |
| 141 } | 149 } |
| 142 | 150 |
| 143 int horizontalIntersect(double axisIntercept, double roots[2]) { | 151 int horizontalIntersect(double axisIntercept, double roots[2]) { |
| 144 double D = quad[2].fY; // f | 152 double D = quad[2].fY; // f |
| 145 double E = quad[1].fY; // e | 153 double E = quad[1].fY; // e |
| 146 double F = quad[0].fY; // d | 154 double F = quad[0].fY; // d |
| 147 D += F - 2 * E; // D = d - 2*e + f | 155 D += F - 2 * E; // D = d - 2*e + f |
| 148 E -= F; // E = -(d - e) | 156 E -= F; // E = -(d - e) |
| 149 F -= axisIntercept; | 157 F -= axisIntercept; |
| 150 return SkDQuad::RootsValidT(D, 2 * E, F, roots); | 158 return SkDQuad::RootsValidT(D, 2 * E, F, roots); |
| 151 } | 159 } |
| 152 | 160 |
| 153 int horizontalIntersect(double axisIntercept, double left, double right, boo
l flipped) { | 161 int horizontalIntersect(double axisIntercept, double left, double right, boo
l flipped) { |
| 154 addHorizontalEndPoints(left, right, axisIntercept); | 162 addExactHorizontalEndPoints(left, right, axisIntercept); |
| 155 double rootVals[2]; | 163 double rootVals[2]; |
| 156 int roots = horizontalIntersect(axisIntercept, rootVals); | 164 int roots = horizontalIntersect(axisIntercept, rootVals); |
| 157 for (int index = 0; index < roots; ++index) { | 165 for (int index = 0; index < roots; ++index) { |
| 158 double quadT = rootVals[index]; | 166 double quadT = rootVals[index]; |
| 159 SkDPoint pt = quad.xyAtT(quadT); | 167 SkDPoint pt = quad.xyAtT(quadT); |
| 160 double lineT = (pt.fX - left) / (right - left); | 168 double lineT = (pt.fX - left) / (right - left); |
| 161 if (PinTs(&quadT, &lineT)) { | 169 if (PinTs(&quadT, &lineT)) { |
| 162 intersections->insert(quadT, lineT, pt); | 170 intersections->insert(quadT, lineT, pt); |
| 163 } | 171 } |
| 164 } | 172 } |
| 173 if (fAllowNear) { |
| 174 addNearHorizontalEndPoints(left, right, axisIntercept); |
| 175 } |
| 165 if (flipped) { | 176 if (flipped) { |
| 166 intersections->flip(); | 177 intersections->flip(); |
| 167 } | 178 } |
| 168 return intersections->used(); | 179 return intersections->used(); |
| 169 } | 180 } |
| 170 | 181 |
| 171 int verticalIntersect(double axisIntercept, double roots[2]) { | 182 int verticalIntersect(double axisIntercept, double roots[2]) { |
| 172 double D = quad[2].fX; // f | 183 double D = quad[2].fX; // f |
| 173 double E = quad[1].fX; // e | 184 double E = quad[1].fX; // e |
| 174 double F = quad[0].fX; // d | 185 double F = quad[0].fX; // d |
| 175 D += F - 2 * E; // D = d - 2*e + f | 186 D += F - 2 * E; // D = d - 2*e + f |
| 176 E -= F; // E = -(d - e) | 187 E -= F; // E = -(d - e) |
| 177 F -= axisIntercept; | 188 F -= axisIntercept; |
| 178 return SkDQuad::RootsValidT(D, 2 * E, F, roots); | 189 return SkDQuad::RootsValidT(D, 2 * E, F, roots); |
| 179 } | 190 } |
| 180 | 191 |
| 181 int verticalIntersect(double axisIntercept, double top, double bottom, bool
flipped) { | 192 int verticalIntersect(double axisIntercept, double top, double bottom, bool
flipped) { |
| 182 addVerticalEndPoints(top, bottom, axisIntercept); | 193 addExactVerticalEndPoints(top, bottom, axisIntercept); |
| 183 double rootVals[2]; | 194 double rootVals[2]; |
| 184 int roots = verticalIntersect(axisIntercept, rootVals); | 195 int roots = verticalIntersect(axisIntercept, rootVals); |
| 185 for (int index = 0; index < roots; ++index) { | 196 for (int index = 0; index < roots; ++index) { |
| 186 double quadT = rootVals[index]; | 197 double quadT = rootVals[index]; |
| 187 SkDPoint pt = quad.xyAtT(quadT); | 198 SkDPoint pt = quad.xyAtT(quadT); |
| 188 double lineT = (pt.fY - top) / (bottom - top); | 199 double lineT = (pt.fY - top) / (bottom - top); |
| 189 if (PinTs(&quadT, &lineT)) { | 200 if (PinTs(&quadT, &lineT)) { |
| 190 intersections->insert(quadT, lineT, pt); | 201 intersections->insert(quadT, lineT, pt); |
| 191 } | 202 } |
| 192 } | 203 } |
| 204 if (fAllowNear) { |
| 205 addNearVerticalEndPoints(top, bottom, axisIntercept); |
| 206 } |
| 193 if (flipped) { | 207 if (flipped) { |
| 194 intersections->flip(); | 208 intersections->flip(); |
| 195 } | 209 } |
| 196 return intersections->used(); | 210 return intersections->used(); |
| 197 } | 211 } |
| 198 | 212 |
| 199 protected: | 213 protected: |
| 200 // add endpoints first to get zero and one t values exactly | 214 // add endpoints first to get zero and one t values exactly |
| 201 void addEndPoints() { | 215 void addExactEndPoints() { |
| 202 for (int qIndex = 0; qIndex < 3; qIndex += 2) { | 216 for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
| 203 bool foundEnd = false; | 217 double lineT = line.exactPoint(quad[qIndex]); |
| 204 for (int lIndex = 0; lIndex < 2; lIndex++) { | 218 if (lineT < 0) { |
| 205 if (quad[qIndex] == line[lIndex]) { | |
| 206 intersections->insert(qIndex >> 1, lIndex, line[lIndex]); | |
| 207 foundEnd = true; | |
| 208 } | |
| 209 } | |
| 210 if (foundEnd) { | |
| 211 continue; | 219 continue; |
| 212 } | 220 } |
| 213 // See if the quad end touches the line. | 221 double quadT = (double) (qIndex >> 1); |
| 214 double dist = line.isLeft(quad[qIndex]); // this distance isn't cart
esian | 222 intersections->insert(quadT, lineT, quad[qIndex]); |
| 215 SkDVector lineLen = line[1] - line[0]; // the x/y magnitudes of the
line | |
| 216 // compute the ULPS of the larger of the x/y deltas | |
| 217 double larger = SkTMax(SkTAbs(lineLen.fX), SkTAbs(lineLen.fY)); | |
| 218 if (!RoughlyEqualUlps(larger, larger + dist)) { // is the dist withi
n ULPS tolerance? | |
| 219 continue; | |
| 220 } | |
| 221 double lineT = findLineT(qIndex >> 1); | |
| 222 if (!between(0, lineT, 1)) { | |
| 223 continue; | |
| 224 } | |
| 225 SkDPoint linePt = line.xyAtT(lineT); | |
| 226 if (linePt.approximatelyEqual(quad[qIndex])) { | |
| 227 intersections->insert(qIndex >> 1, lineT, quad[qIndex]); | |
| 228 } | |
| 229 } | 223 } |
| 230 } | 224 } |
| 231 | 225 |
| 232 void addHorizontalEndPoints(double left, double right, double y) { | 226 void addNearEndPoints() { |
| 233 for (int qIndex = 0; qIndex < 3; qIndex += 2) { | 227 for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
| 234 if (!AlmostEqualUlps(quad[qIndex].fY, y)) { | 228 double quadT = (double) (qIndex >> 1); |
| 229 if (intersections->hasT(quadT)) { |
| 235 continue; | 230 continue; |
| 236 } | 231 } |
| 237 double x = quad[qIndex].fX; | 232 double lineT = line.nearPoint(quad[qIndex]); |
| 238 if (between(left, x, right)) { | 233 if (lineT < 0) { |
| 239 double t = (x - left) / (right - left); | 234 continue; |
| 240 intersections->insert(qIndex >> 1, t, quad[qIndex]); | |
| 241 } | 235 } |
| 236 intersections->insert(quadT, lineT, quad[qIndex]); |
| 237 } |
| 238 // FIXME: see if line end is nearly on quad |
| 239 } |
| 240 |
| 241 void addExactHorizontalEndPoints(double left, double right, double y) { |
| 242 for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
| 243 double lineT = SkDLine::ExactPointH(quad[qIndex], left, right, y); |
| 244 if (lineT < 0) { |
| 245 continue; |
| 246 } |
| 247 double quadT = (double) (qIndex >> 1); |
| 248 intersections->insert(quadT, lineT, quad[qIndex]); |
| 242 } | 249 } |
| 243 } | 250 } |
| 244 | 251 |
| 245 void addVerticalEndPoints(double top, double bottom, double x) { | 252 void addNearHorizontalEndPoints(double left, double right, double y) { |
| 246 for (int qIndex = 0; qIndex < 3; qIndex += 2) { | 253 for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
| 247 if (!AlmostEqualUlps(quad[qIndex].fX, x)) { | 254 double quadT = (double) (qIndex >> 1); |
| 255 if (intersections->hasT(quadT)) { |
| 248 continue; | 256 continue; |
| 249 } | 257 } |
| 250 double y = quad[qIndex].fY; | 258 double lineT = SkDLine::NearPointH(quad[qIndex], left, right, y); |
| 251 if (between(top, y, bottom)) { | 259 if (lineT < 0) { |
| 252 double t = (y - top) / (bottom - top); | 260 continue; |
| 253 intersections->insert(qIndex >> 1, t, quad[qIndex]); | |
| 254 } | 261 } |
| 262 intersections->insert(quadT, lineT, quad[qIndex]); |
| 255 } | 263 } |
| 264 // FIXME: see if line end is nearly on quad |
| 265 } |
| 266 |
| 267 void addExactVerticalEndPoints(double top, double bottom, double x) { |
| 268 for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
| 269 double lineT = SkDLine::ExactPointV(quad[qIndex], top, bottom, x); |
| 270 if (lineT < 0) { |
| 271 continue; |
| 272 } |
| 273 double quadT = (double) (qIndex >> 1); |
| 274 intersections->insert(quadT, lineT, quad[qIndex]); |
| 275 } |
| 276 } |
| 277 |
| 278 void addNearVerticalEndPoints(double top, double bottom, double x) { |
| 279 for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
| 280 double quadT = (double) (qIndex >> 1); |
| 281 if (intersections->hasT(quadT)) { |
| 282 continue; |
| 283 } |
| 284 double lineT = SkDLine::NearPointV(quad[qIndex], top, bottom, x); |
| 285 if (lineT < 0) { |
| 286 continue; |
| 287 } |
| 288 intersections->insert(quadT, lineT, quad[qIndex]); |
| 289 } |
| 290 // FIXME: see if line end is nearly on quad |
| 256 } | 291 } |
| 257 | 292 |
| 258 double findLineT(double t) { | 293 double findLineT(double t) { |
| 259 SkDPoint xy = quad.xyAtT(t); | 294 SkDPoint xy = quad.xyAtT(t); |
| 260 double dx = line[1].fX - line[0].fX; | 295 double dx = line[1].fX - line[0].fX; |
| 261 double dy = line[1].fY - line[0].fY; | 296 double dy = line[1].fY - line[0].fY; |
| 262 #if 0 | |
| 263 if (fabs(dx) > fabs(dy)) { | |
| 264 return (xy.fX - line[0].fX) / dx; | |
| 265 } | |
| 266 return (xy.fY - line[0].fY) / dy; | |
| 267 #else | |
| 268 double dxT = (xy.fX - line[0].fX) / dx; | 297 double dxT = (xy.fX - line[0].fX) / dx; |
| 269 double dyT = (xy.fY - line[0].fY) / dy; | 298 double dyT = (xy.fY - line[0].fY) / dy; |
| 270 if (!between(FLT_EPSILON, dxT, 1 - FLT_EPSILON) && between(0, dyT, 1)) { | 299 if (!between(FLT_EPSILON, dxT, 1 - FLT_EPSILON) && between(0, dyT, 1)) { |
| 271 return dyT; | 300 return dyT; |
| 272 } | 301 } |
| 273 if (!between(FLT_EPSILON, dyT, 1 - FLT_EPSILON) && between(0, dxT, 1)) { | 302 if (!between(FLT_EPSILON, dyT, 1 - FLT_EPSILON) && between(0, dxT, 1)) { |
| 274 return dxT; | 303 return dxT; |
| 275 } | 304 } |
| 276 return fabs(dx) > fabs(dy) ? dxT : dyT; | 305 return fabs(dx) > fabs(dy) ? dxT : dyT; |
| 277 #endif | |
| 278 } | 306 } |
| 279 | 307 |
| 280 static bool PinTs(double* quadT, double* lineT) { | 308 static bool PinTs(double* quadT, double* lineT) { |
| 281 if (!approximately_one_or_less(*lineT)) { | 309 if (!approximately_one_or_less(*lineT)) { |
| 282 return false; | 310 return false; |
| 283 } | 311 } |
| 284 if (!approximately_zero_or_more(*lineT)) { | 312 if (!approximately_zero_or_more(*lineT)) { |
| 285 return false; | 313 return false; |
| 286 } | 314 } |
| 287 if (precisely_less_than_zero(*quadT)) { | 315 *quadT = SkPinT(*quadT); |
| 288 *quadT = 0; | 316 *lineT = SkPinT(*lineT); |
| 289 } else if (precisely_greater_than_one(*quadT)) { | |
| 290 *quadT = 1; | |
| 291 } | |
| 292 if (precisely_less_than_zero(*lineT)) { | |
| 293 *lineT = 0; | |
| 294 } else if (precisely_greater_than_one(*lineT)) { | |
| 295 *lineT = 1; | |
| 296 } | |
| 297 return true; | 317 return true; |
| 298 } | 318 } |
| 299 | 319 |
| 300 private: | 320 private: |
| 301 const SkDQuad& quad; | 321 const SkDQuad& quad; |
| 302 const SkDLine& line; | 322 const SkDLine& line; |
| 303 SkIntersections* intersections; | 323 SkIntersections* intersections; |
| 324 bool fAllowNear; |
| 304 }; | 325 }; |
| 305 | 326 |
| 306 // utility for pairs of coincident quads | 327 // utility for pairs of coincident quads |
| 307 static double horizontalIntersect(const SkDQuad& quad, const SkDPoint& pt) { | 328 static double horizontalIntersect(const SkDQuad& quad, const SkDPoint& pt) { |
| 308 LineQuadraticIntersections q(quad, *(static_cast<SkDLine*>(0)), | 329 LineQuadraticIntersections q(quad, *(static_cast<SkDLine*>(0)), |
| 309 static_cast<SkIntersections*>(0)); | 330 static_cast<SkIntersections*>(0)); |
| 310 double rootVals[2]; | 331 double rootVals[2]; |
| 311 int roots = q.horizontalIntersect(pt.fY, rootVals); | 332 int roots = q.horizontalIntersect(pt.fY, rootVals); |
| 312 for (int index = 0; index < roots; ++index) { | 333 for (int index = 0; index < roots; ++index) { |
| 313 double t = rootVals[index]; | 334 double t = rootVals[index]; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 348 } | 369 } |
| 349 | 370 |
| 350 int SkIntersections::vertical(const SkDQuad& quad, double top, double bottom, do
uble x, | 371 int SkIntersections::vertical(const SkDQuad& quad, double top, double bottom, do
uble x, |
| 351 bool flipped) { | 372 bool flipped) { |
| 352 LineQuadraticIntersections q(quad, *(static_cast<SkDLine*>(0)), this); | 373 LineQuadraticIntersections q(quad, *(static_cast<SkDLine*>(0)), this); |
| 353 return q.verticalIntersect(x, top, bottom, flipped); | 374 return q.verticalIntersect(x, top, bottom, flipped); |
| 354 } | 375 } |
| 355 | 376 |
| 356 int SkIntersections::intersect(const SkDQuad& quad, const SkDLine& line) { | 377 int SkIntersections::intersect(const SkDQuad& quad, const SkDLine& line) { |
| 357 LineQuadraticIntersections q(quad, line, this); | 378 LineQuadraticIntersections q(quad, line, this); |
| 379 q.allowNear(fAllowNear); |
| 358 return q.intersect(); | 380 return q.intersect(); |
| 359 } | 381 } |
| 360 | 382 |
| 361 int SkIntersections::intersectRay(const SkDQuad& quad, const SkDLine& line) { | 383 int SkIntersections::intersectRay(const SkDQuad& quad, const SkDLine& line) { |
| 362 LineQuadraticIntersections q(quad, line, this); | 384 LineQuadraticIntersections q(quad, line, this); |
| 363 fUsed = q.intersectRay(fT[0]); | 385 fUsed = q.intersectRay(fT[0]); |
| 364 for (int index = 0; index < fUsed; ++index) { | 386 for (int index = 0; index < fUsed; ++index) { |
| 365 fPt[index] = quad.xyAtT(fT[0][index]); | 387 fPt[index] = quad.xyAtT(fT[0][index]); |
| 366 } | 388 } |
| 367 return fUsed; | 389 return fUsed; |
| 368 } | 390 } |
| OLD | NEW |