| 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 | 9 |
| 10 /* Determine the intersection point of two lines. This assumes the lines are not
parallel, | |
| 11 and that that the lines are infinite. | |
| 12 From http://en.wikipedia.org/wiki/Line-line_intersection | |
| 13 */ | |
| 14 SkDPoint SkIntersections::Line(const SkDLine& a, const SkDLine& b) { | |
| 15 double axLen = a[1].fX - a[0].fX; | |
| 16 double ayLen = a[1].fY - a[0].fY; | |
| 17 double bxLen = b[1].fX - b[0].fX; | |
| 18 double byLen = b[1].fY - b[0].fY; | |
| 19 double denom = byLen * axLen - ayLen * bxLen; | |
| 20 SkASSERT(denom); | |
| 21 double term1 = a[1].fX * a[0].fY - a[1].fY * a[0].fX; | |
| 22 double term2 = b[1].fX * b[0].fY - b[1].fY * b[0].fX; | |
| 23 SkDPoint p; | |
| 24 p.fX = (term1 * bxLen - axLen * term2) / denom; | |
| 25 p.fY = (term1 * byLen - ayLen * term2) / denom; | |
| 26 return p; | |
| 27 } | |
| 28 | |
| 29 int SkIntersections::cleanUpCoincidence() { | |
| 30 do { | |
| 31 int last = fUsed - 1; | |
| 32 for (int index = 0; index < last; ++index) { | |
| 33 if (fT[0][index] == fT[0][index + 1]) { | |
| 34 removeOne(index + (int) (fT[1][index] == 0 || fT[1][index] == 1)
); | |
| 35 goto tryAgain; | |
| 36 } | |
| 37 } | |
| 38 for (int index = 0; index < last; ++index) { | |
| 39 if (fT[1][index] == fT[1][index + 1]) { | |
| 40 removeOne(index + (int) (fT[0][index] == 0 || fT[0][index] == 1)
); | |
| 41 goto tryAgain; | |
| 42 } | |
| 43 } | |
| 44 return fUsed; | |
| 45 tryAgain: ; | |
| 46 } while (true); | |
| 47 } | |
| 48 | |
| 49 void SkIntersections::cleanUpParallelLines(bool parallel) { | 10 void SkIntersections::cleanUpParallelLines(bool parallel) { |
| 50 while (fUsed > 2) { | 11 while (fUsed > 2) { |
| 51 removeOne(1); | 12 removeOne(1); |
| 52 } | 13 } |
| 53 if (fUsed == 2 && !parallel) { | 14 if (fUsed == 2 && !parallel) { |
| 54 bool startMatch = fT[0][0] == 0 || fT[1][0] == 0 || fT[1][0] == 1; | 15 bool startMatch = fT[0][0] == 0 || fT[1][0] == 0 || fT[1][0] == 1; |
| 55 bool endMatch = fT[0][1] == 1 || fT[1][1] == 0 || fT[1][1] == 1; | 16 bool endMatch = fT[0][1] == 1 || fT[1][1] == 0 || fT[1][1] == 1; |
| 56 if ((!startMatch && !endMatch) || approximately_equal(fT[0][0], fT[0][1]
)) { | 17 if ((!startMatch && !endMatch) || approximately_equal(fT[0][0], fT[0][1]
)) { |
| 57 SkASSERT(startMatch || endMatch); | 18 SkASSERT(startMatch || endMatch); |
| 58 removeOne(endMatch); | 19 removeOne(endMatch); |
| 59 } | 20 } |
| 60 } | 21 } |
| 22 if (fUsed == 2) { |
| 23 fIsCoincident[0] = fIsCoincident[1] = 0x03; |
| 24 } |
| 61 } | 25 } |
| 62 | 26 |
| 63 void SkIntersections::computePoints(const SkDLine& line, int used) { | 27 void SkIntersections::computePoints(const SkDLine& line, int used) { |
| 64 fPt[0] = line.ptAtT(fT[0][0]); | 28 fPt[0] = line.ptAtT(fT[0][0]); |
| 65 if ((fUsed = used) == 2) { | 29 if ((fUsed = used) == 2) { |
| 66 fPt[1] = line.ptAtT(fT[0][1]); | 30 fPt[1] = line.ptAtT(fT[0][1]); |
| 67 } | 31 } |
| 68 } | 32 } |
| 69 | 33 |
| 70 int SkIntersections::intersectRay(const SkDLine& a, const SkDLine& b) { | 34 int SkIntersections::intersectRay(const SkDLine& a, const SkDLine& b) { |
| 71 fMax = 2; | 35 fMax = 2; |
| 72 SkDVector aLen = a[1] - a[0]; | 36 SkDVector aLen = a[1] - a[0]; |
| 73 SkDVector bLen = b[1] - b[0]; | 37 SkDVector bLen = b[1] - b[0]; |
| 74 /* Slopes match when denom goes to zero: | 38 /* Slopes match when denom goes to zero: |
| 75 axLen / ayLen == bxLen / byLen | 39 axLen / ayLen == bxLen / byLen |
| 76 (ayLen * byLen) * axLen / ayLen == (ayLen * byLen) * bxLen / byLen | 40 (ayLen * byLen) * axLen / ayLen == (ayLen * byLen) * bxLen / byLen |
| 77 byLen * axLen == ayLen * bxLen | 41 byLen * axLen == ayLen * bxLen |
| 78 byLen * axLen - ayLen * bxLen == 0 ( == denom ) | 42 byLen * axLen - ayLen * bxLen == 0 ( == denom ) |
| 79 */ | 43 */ |
| 80 double denom = bLen.fY * aLen.fX - aLen.fY * bLen.fX; | 44 double denom = bLen.fY * aLen.fX - aLen.fY * bLen.fX; |
| 81 SkDVector ab0 = a[0] - b[0]; | 45 SkDVector ab0 = a[0] - b[0]; |
| 82 double numerA = ab0.fY * bLen.fX - bLen.fY * ab0.fX; | 46 double numerA = ab0.fY * bLen.fX - bLen.fY * ab0.fX; |
| 83 double numerB = ab0.fY * aLen.fX - aLen.fY * ab0.fX; | 47 double numerB = ab0.fY * aLen.fX - aLen.fY * ab0.fX; |
| 84 #if 0 | |
| 85 if (!between(0, numerA, denom) || !between(0, numerB, denom)) { | |
| 86 fUsed = 0; | |
| 87 return 0; | |
| 88 } | |
| 89 #endif | |
| 90 numerA /= denom; | 48 numerA /= denom; |
| 91 numerB /= denom; | 49 numerB /= denom; |
| 92 int used; | 50 int used; |
| 93 if (!approximately_zero(denom)) { | 51 if (!approximately_zero(denom)) { |
| 94 fT[0][0] = numerA; | 52 fT[0][0] = numerA; |
| 95 fT[1][0] = numerB; | 53 fT[1][0] = numerB; |
| 96 used = 1; | 54 used = 1; |
| 97 } else { | 55 } else { |
| 98 /* See if the axis intercepts match: | 56 /* See if the axis intercepts match: |
| 99 ay - ax * ayLen / axLen == by - bx * ayLen / axLen | 57 ay - ax * ayLen / axLen == by - bx * ayLen / axLen |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 for (int iA = 0; iA < 2; ++iA) { | 141 for (int iA = 0; iA < 2; ++iA) { |
| 184 if (!aNotB[iA]) { | 142 if (!aNotB[iA]) { |
| 185 continue; | 143 continue; |
| 186 } | 144 } |
| 187 int nearer = aNearB[iA] > 0.5; | 145 int nearer = aNearB[iA] > 0.5; |
| 188 if (!bNotA[nearer]) { | 146 if (!bNotA[nearer]) { |
| 189 continue; | 147 continue; |
| 190 } | 148 } |
| 191 SkASSERT(a[iA] != b[nearer]); | 149 SkASSERT(a[iA] != b[nearer]); |
| 192 SkASSERT(iA == (bNearA[nearer] > 0.5)); | 150 SkASSERT(iA == (bNearA[nearer] > 0.5)); |
| 193 fNearlySame[iA] = true; | |
| 194 insertNear(iA, nearer, a[iA], b[nearer]); | 151 insertNear(iA, nearer, a[iA], b[nearer]); |
| 195 aNearB[iA] = -1; | 152 aNearB[iA] = -1; |
| 196 bNearA[nearer] = -1; | 153 bNearA[nearer] = -1; |
| 197 nearCount -= 2; | 154 nearCount -= 2; |
| 198 } | 155 } |
| 199 } | 156 } |
| 200 if (nearCount > 0) { | 157 if (nearCount > 0) { |
| 201 for (int iA = 0; iA < 2; ++iA) { | 158 for (int iA = 0; iA < 2; ++iA) { |
| 202 if (aNearB[iA] >= 0) { | 159 if (aNearB[iA] >= 0) { |
| 203 insert(iA, aNearB[iA], a[iA]); | 160 insert(iA, aNearB[iA], a[iA]); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 228 if (AlmostEqualUlps(min, max) && max - min < fabs(line[0].fX - line[1].fX))
{ | 185 if (AlmostEqualUlps(min, max) && max - min < fabs(line[0].fX - line[1].fX))
{ |
| 229 return 2; | 186 return 2; |
| 230 } | 187 } |
| 231 return 1; | 188 return 1; |
| 232 } | 189 } |
| 233 | 190 |
| 234 static double horizontal_intercept(const SkDLine& line, double y) { | 191 static double horizontal_intercept(const SkDLine& line, double y) { |
| 235 return SkPinT((y - line[0].fY) / (line[1].fY - line[0].fY)); | 192 return SkPinT((y - line[0].fY) / (line[1].fY - line[0].fY)); |
| 236 } | 193 } |
| 237 | 194 |
| 238 int SkIntersections::horizontal(const SkDLine& line, double y) { | |
| 239 fMax = 2; | |
| 240 int horizontalType = horizontal_coincident(line, y); | |
| 241 if (horizontalType == 1) { | |
| 242 fT[0][0] = horizontal_intercept(line, y); | |
| 243 } else if (horizontalType == 2) { | |
| 244 fT[0][0] = 0; | |
| 245 fT[0][1] = 1; | |
| 246 } | |
| 247 return fUsed = horizontalType; | |
| 248 } | |
| 249 | |
| 250 int SkIntersections::horizontal(const SkDLine& line, double left, double right, | 195 int SkIntersections::horizontal(const SkDLine& line, double left, double right, |
| 251 double y, bool flipped) { | 196 double y, bool flipped) { |
| 252 fMax = 3; // clean up parallel at the end will limit the result to 2 at the
most | 197 fMax = 3; // clean up parallel at the end will limit the result to 2 at the
most |
| 253 // see if end points intersect the opposite line | 198 // see if end points intersect the opposite line |
| 254 double t; | 199 double t; |
| 255 const SkDPoint leftPt = { left, y }; | 200 const SkDPoint leftPt = { left, y }; |
| 256 if ((t = line.exactPoint(leftPt)) >= 0) { | 201 if ((t = line.exactPoint(leftPt)) >= 0) { |
| 257 insert(t, (double) flipped, leftPt); | 202 insert(t, (double) flipped, leftPt); |
| 258 } | 203 } |
| 259 if (left != right) { | 204 if (left != right) { |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 316 if (AlmostEqualUlps(min, max)) { | 261 if (AlmostEqualUlps(min, max)) { |
| 317 return 2; | 262 return 2; |
| 318 } | 263 } |
| 319 return 1; | 264 return 1; |
| 320 } | 265 } |
| 321 | 266 |
| 322 static double vertical_intercept(const SkDLine& line, double x) { | 267 static double vertical_intercept(const SkDLine& line, double x) { |
| 323 return SkPinT((x - line[0].fX) / (line[1].fX - line[0].fX)); | 268 return SkPinT((x - line[0].fX) / (line[1].fX - line[0].fX)); |
| 324 } | 269 } |
| 325 | 270 |
| 326 int SkIntersections::vertical(const SkDLine& line, double x) { | |
| 327 fMax = 2; | |
| 328 int verticalType = vertical_coincident(line, x); | |
| 329 if (verticalType == 1) { | |
| 330 fT[0][0] = vertical_intercept(line, x); | |
| 331 } else if (verticalType == 2) { | |
| 332 fT[0][0] = 0; | |
| 333 fT[0][1] = 1; | |
| 334 } | |
| 335 return fUsed = verticalType; | |
| 336 } | |
| 337 | |
| 338 int SkIntersections::vertical(const SkDLine& line, double top, double bottom, | 271 int SkIntersections::vertical(const SkDLine& line, double top, double bottom, |
| 339 double x, bool flipped) { | 272 double x, bool flipped) { |
| 340 fMax = 3; // cleanup parallel lines will bring this back line | 273 fMax = 3; // cleanup parallel lines will bring this back line |
| 341 // see if end points intersect the opposite line | 274 // see if end points intersect the opposite line |
| 342 double t; | 275 double t; |
| 343 SkDPoint topPt = { x, top }; | 276 SkDPoint topPt = { x, top }; |
| 344 if ((t = line.exactPoint(topPt)) >= 0) { | 277 if ((t = line.exactPoint(topPt)) >= 0) { |
| 345 insert(t, (double) flipped, topPt); | 278 insert(t, (double) flipped, topPt); |
| 346 } | 279 } |
| 347 if (top != bottom) { | 280 if (top != bottom) { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 386 insert((double) index, flipped ? 1 - t : t, line[index]); | 319 insert((double) index, flipped ? 1 - t : t, line[index]); |
| 387 } | 320 } |
| 388 } | 321 } |
| 389 } | 322 } |
| 390 } | 323 } |
| 391 cleanUpParallelLines(result == 2); | 324 cleanUpParallelLines(result == 2); |
| 392 SkASSERT(fUsed <= 2); | 325 SkASSERT(fUsed <= 2); |
| 393 return fUsed; | 326 return fUsed; |
| 394 } | 327 } |
| 395 | 328 |
| 396 // from http://www.bryceboe.com/wordpress/wp-content/uploads/2006/10/intersect.p
y | |
| 397 // 4 subs, 2 muls, 1 cmp | |
| 398 static bool ccw(const SkDPoint& A, const SkDPoint& B, const SkDPoint& C) { | |
| 399 return (C.fY - A.fY) * (B.fX - A.fX) > (B.fY - A.fY) * (C.fX - A.fX); | |
| 400 } | |
| 401 | |
| 402 // 16 subs, 8 muls, 6 cmps | |
| 403 bool SkIntersections::Test(const SkDLine& a, const SkDLine& b) { | |
| 404 return ccw(a[0], b[0], b[1]) != ccw(a[1], b[0], b[1]) | |
| 405 && ccw(a[0], a[1], b[0]) != ccw(a[0], a[1], b[1]); | |
| 406 } | |
| OLD | NEW |