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 |