blob: 9ae0107173926e923b1936fd883d1953377ebd18 [file] [log] [blame]
caryclark@google.com07393ca2013-04-08 11:47:37 +00001/*
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 "SkPathOpsLine.h"
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 */
14SkDPoint 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
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000029void SkIntersections::cleanUpCoincidence() {
30 SkASSERT(fUsed == 2);
31 // both t values are good
32 bool startMatch = fT[0][0] == 0 && (fT[1][0] == 0 || fT[1][0] == 1);
33 bool endMatch = fT[0][1] == 1 && (fT[1][1] == 0 || fT[1][1] == 1);
34 if (startMatch || endMatch) {
35 removeOne(startMatch);
36 return;
37 }
38 // either t value is good
39 bool pStartMatch = fT[0][0] == 0 || fT[1][0] == 0 || fT[1][0] == 1;
40 bool pEndMatch = fT[0][1] == 1 || fT[1][1] == 0 || fT[1][1] == 1;
41 removeOne(pStartMatch || !pEndMatch);
42}
43
44void SkIntersections::cleanUpParallelLines(bool parallel) {
45 while (fUsed > 2) {
46 removeOne(1);
47 }
48 if (fUsed == 2 && !parallel) {
49 bool startMatch = fT[0][0] == 0 || fT[1][0] == 0 || fT[1][0] == 1;
50 bool endMatch = fT[0][1] == 1 || fT[1][1] == 0 || fT[1][1] == 1;
51 if ((!startMatch && !endMatch) || approximately_equal(fT[0][0], fT[0][1])) {
52 SkASSERT(startMatch || endMatch);
53 removeOne(endMatch);
54 }
55 }
56}
57
58void SkIntersections::computePoints(const SkDLine& line, int used) {
caryclark@google.com4fdbb222013-07-23 15:27:41 +000059 fPt[0] = line.ptAtT(fT[0][0]);
caryclark@google.com07393ca2013-04-08 11:47:37 +000060 if ((fUsed = used) == 2) {
caryclark@google.com4fdbb222013-07-23 15:27:41 +000061 fPt[1] = line.ptAtT(fT[0][1]);
caryclark@google.com07393ca2013-04-08 11:47:37 +000062 }
caryclark@google.com07393ca2013-04-08 11:47:37 +000063}
64
caryclark@google.comcffbcc32013-06-04 17:59:42 +000065int SkIntersections::intersectRay(const SkDLine& a, const SkDLine& b) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000066 fMax = 2;
caryclark@google.com570863f2013-09-16 15:55:01 +000067 SkDVector aLen = a[1] - a[0];
68 SkDVector bLen = b[1] - b[0];
caryclark@google.comcffbcc32013-06-04 17:59:42 +000069 /* Slopes match when denom goes to zero:
70 axLen / ayLen == bxLen / byLen
71 (ayLen * byLen) * axLen / ayLen == (ayLen * byLen) * bxLen / byLen
72 byLen * axLen == ayLen * bxLen
73 byLen * axLen - ayLen * bxLen == 0 ( == denom )
74 */
caryclark@google.com570863f2013-09-16 15:55:01 +000075 double denom = bLen.fY * aLen.fX - aLen.fY * bLen.fX;
76 SkDVector ab0 = a[0] - b[0];
77 double numerA = ab0.fY * bLen.fX - bLen.fY * ab0.fX;
78 double numerB = ab0.fY * aLen.fX - aLen.fY * ab0.fX;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000079#if 0
80 if (!between(0, numerA, denom) || !between(0, numerB, denom)) {
81 fUsed = 0;
82 return 0;
83 }
84#endif
caryclark@google.comcffbcc32013-06-04 17:59:42 +000085 numerA /= denom;
86 numerB /= denom;
87 int used;
88 if (!approximately_zero(denom)) {
89 fT[0][0] = numerA;
90 fT[1][0] = numerB;
91 used = 1;
92 } else {
93 /* See if the axis intercepts match:
94 ay - ax * ayLen / axLen == by - bx * ayLen / axLen
95 axLen * (ay - ax * ayLen / axLen) == axLen * (by - bx * ayLen / axLen)
96 axLen * ay - ax * ayLen == axLen * by - bx * ayLen
97 */
caryclark@google.com570863f2013-09-16 15:55:01 +000098 if (!AlmostEqualUlps(aLen.fX * a[0].fY - aLen.fY * a[0].fX,
99 aLen.fX * b[0].fY - aLen.fY * b[0].fX)) {
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000100 return fUsed = 0;
101 }
102 // there's no great answer for intersection points for coincident rays, but return something
103 fT[0][0] = fT[1][0] = 0;
104 fT[1][0] = fT[1][1] = 1;
105 used = 2;
106 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000107 computePoints(a, used);
108 return fUsed;
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000109}
110
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000111// note that this only works if both lines are neither horizontal nor vertical
caryclark@google.com07393ca2013-04-08 11:47:37 +0000112int SkIntersections::intersect(const SkDLine& a, const SkDLine& b) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000113 fMax = 3; // note that we clean up so that there is no more than two in the end
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000114 // see if end points intersect the opposite line
115 double t;
116 for (int iA = 0; iA < 2; ++iA) {
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000117 if ((t = b.exactPoint(a[iA])) >= 0) {
118 insert(iA, t, a[iA]);
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000119 }
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000120 }
121 for (int iB = 0; iB < 2; ++iB) {
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000122 if ((t = a.exactPoint(b[iB])) >= 0) {
123 insert(t, iB, b[iB]);
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000124 }
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000125 }
126 /* Determine the intersection point of two line segments
127 Return FALSE if the lines don't intersect
128 from: http://paulbourke.net/geometry/lineline2d/ */
caryclark@google.com07393ca2013-04-08 11:47:37 +0000129 double axLen = a[1].fX - a[0].fX;
130 double ayLen = a[1].fY - a[0].fY;
131 double bxLen = b[1].fX - b[0].fX;
132 double byLen = b[1].fY - b[0].fY;
133 /* Slopes match when denom goes to zero:
134 axLen / ayLen == bxLen / byLen
135 (ayLen * byLen) * axLen / ayLen == (ayLen * byLen) * bxLen / byLen
136 byLen * axLen == ayLen * bxLen
137 byLen * axLen - ayLen * bxLen == 0 ( == denom )
138 */
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000139 double axByLen = axLen * byLen;
140 double ayBxLen = ayLen * bxLen;
141 // detect parallel lines the same way here and in SkOpAngle operator <
142 // so that non-parallel means they are also sortable
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000143 bool unparallel = fAllowNear ? NotAlmostEqualUlps(axByLen, ayBxLen)
144 : NotAlmostDequalUlps(axByLen, ayBxLen);
145 if (unparallel && fUsed == 0) {
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000146 double ab0y = a[0].fY - b[0].fY;
147 double ab0x = a[0].fX - b[0].fX;
148 double numerA = ab0y * bxLen - byLen * ab0x;
149 double numerB = ab0y * axLen - ayLen * ab0x;
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000150 double denom = axByLen - ayBxLen;
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000151 if (between(0, numerA, denom) && between(0, numerB, denom)) {
152 fT[0][0] = numerA / denom;
153 fT[1][0] = numerB / denom;
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000154 computePoints(a, 1);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000155 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000156 }
caryclarkdac1d172014-06-17 05:15:38 -0700157/* Allow tracking that both sets of end points are near each other -- the lines are entirely
158 coincident -- even when the end points are not exactly the same.
159 Mark this as a 'wild card' for the end points, so that either point is considered totally
160 coincident. Then, avoid folding the lines over each other, but allow either end to mate
161 to the next set of lines.
162 */
caryclark@google.com570863f2013-09-16 15:55:01 +0000163 if (fAllowNear || !unparallel) {
caryclarkdac1d172014-06-17 05:15:38 -0700164 double aNearB[2];
165 double bNearA[2];
166 bool aNotB[2] = {false, false};
167 bool bNotA[2] = {false, false};
168 int nearCount = 0;
169 for (int index = 0; index < 2; ++index) {
170 aNearB[index] = t = b.nearPoint(a[index], &aNotB[index]);
171 nearCount += t >= 0;
172 bNearA[index] = t = a.nearPoint(b[index], &bNotA[index]);
173 nearCount += t >= 0;
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000174 }
caryclarkdac1d172014-06-17 05:15:38 -0700175 if (nearCount > 0) {
176 for (int iA = 0; iA < 2; ++iA) {
177 if (!aNotB[iA]) {
178 continue;
179 }
180 int nearer = aNearB[iA] > 0.5;
181 if (!bNotA[nearer]) {
182 continue;
183 }
184 SkASSERT(a[iA] != b[nearer]);
185 SkASSERT(iA == (bNearA[nearer] > 0.5));
186 fNearlySame[iA] = true;
187 insertNear(iA, nearer, a[iA], b[nearer]);
188 aNearB[iA] = -1;
189 bNearA[nearer] = -1;
190 nearCount -= 2;
191 }
192 if (nearCount > 0) {
193 for (int iA = 0; iA < 2; ++iA) {
194 if (aNearB[iA] >= 0) {
195 insert(iA, aNearB[iA], a[iA]);
196 }
197 }
198 for (int iB = 0; iB < 2; ++iB) {
199 if (bNearA[iB] >= 0) {
200 insert(bNearA[iB], iB, b[iB]);
201 }
202 }
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000203 }
204 }
205 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000206 cleanUpParallelLines(!unparallel);
207 SkASSERT(fUsed <= 2);
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000208 return fUsed;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000209}
210
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000211static int horizontal_coincident(const SkDLine& line, double y) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000212 double min = line[0].fY;
213 double max = line[1].fY;
214 if (min > max) {
215 SkTSwap(min, max);
216 }
217 if (min > y || max < y) {
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000218 return 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000219 }
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000220 if (AlmostEqualUlps(min, max) && max - min < fabs(line[0].fX - line[1].fX)) {
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000221 return 2;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000222 }
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000223 return 1;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000224}
225
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000226static double horizontal_intercept(const SkDLine& line, double y) {
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000227 return SkPinT((y - line[0].fY) / (line[1].fY - line[0].fY));
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000228}
229
230int SkIntersections::horizontal(const SkDLine& line, double y) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000231 fMax = 2;
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000232 int horizontalType = horizontal_coincident(line, y);
233 if (horizontalType == 1) {
234 fT[0][0] = horizontal_intercept(line, y);
235 } else if (horizontalType == 2) {
236 fT[0][0] = 0;
237 fT[0][1] = 1;
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000238 }
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000239 return fUsed = horizontalType;
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000240}
241
caryclark@google.com07393ca2013-04-08 11:47:37 +0000242int SkIntersections::horizontal(const SkDLine& line, double left, double right,
243 double y, bool flipped) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000244 fMax = 3; // clean up parallel at the end will limit the result to 2 at the most
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000245 // see if end points intersect the opposite line
246 double t;
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000247 const SkDPoint leftPt = { left, y };
248 if ((t = line.exactPoint(leftPt)) >= 0) {
249 insert(t, (double) flipped, leftPt);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000250 }
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000251 if (left != right) {
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000252 const SkDPoint rightPt = { right, y };
253 if ((t = line.exactPoint(rightPt)) >= 0) {
254 insert(t, (double) !flipped, rightPt);
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000255 }
256 for (int index = 0; index < 2; ++index) {
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000257 if ((t = SkDLine::ExactPointH(line[index], left, right, y)) >= 0) {
258 insert((double) index, flipped ? 1 - t : t, line[index]);
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000259 }
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000260 }
261 }
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000262 int result = horizontal_coincident(line, y);
263 if (result == 1 && fUsed == 0) {
264 fT[0][0] = horizontal_intercept(line, y);
265 double xIntercept = line[0].fX + fT[0][0] * (line[1].fX - line[0].fX);
266 if (between(left, xIntercept, right)) {
267 fT[1][0] = (xIntercept - left) / (right - left);
268 if (flipped) {
269 // OPTIMIZATION: ? instead of swapping, pass original line, use [1].fX - [0].fX
270 for (int index = 0; index < result; ++index) {
271 fT[1][index] = 1 - fT[1][index];
272 }
273 }
caryclark@google.com15107262013-11-08 18:00:01 +0000274 fPt[0].fX = xIntercept;
275 fPt[0].fY = y;
276 fUsed = 1;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000277 }
278 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000279 if (fAllowNear || result == 2) {
caryclarkdac1d172014-06-17 05:15:38 -0700280 if ((t = line.nearPoint(leftPt, NULL)) >= 0) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000281 insert(t, (double) flipped, leftPt);
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000282 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000283 if (left != right) {
284 const SkDPoint rightPt = { right, y };
caryclarkdac1d172014-06-17 05:15:38 -0700285 if ((t = line.nearPoint(rightPt, NULL)) >= 0) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000286 insert(t, (double) !flipped, rightPt);
287 }
288 for (int index = 0; index < 2; ++index) {
289 if ((t = SkDLine::NearPointH(line[index], left, right, y)) >= 0) {
290 insert((double) index, flipped ? 1 - t : t, line[index]);
291 }
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000292 }
293 }
294 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000295 cleanUpParallelLines(result == 2);
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000296 return fUsed;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000297}
298
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000299static int vertical_coincident(const SkDLine& line, double x) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000300 double min = line[0].fX;
301 double max = line[1].fX;
302 if (min > max) {
303 SkTSwap(min, max);
304 }
caryclark@google.com03610322013-04-18 15:58:21 +0000305 if (!precisely_between(min, x, max)) {
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000306 return 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000307 }
308 if (AlmostEqualUlps(min, max)) {
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000309 return 2;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000310 }
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000311 return 1;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000312}
313
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000314static double vertical_intercept(const SkDLine& line, double x) {
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000315 return SkPinT((x - line[0].fX) / (line[1].fX - line[0].fX));
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000316}
317
318int SkIntersections::vertical(const SkDLine& line, double x) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000319 fMax = 2;
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000320 int verticalType = vertical_coincident(line, x);
321 if (verticalType == 1) {
322 fT[0][0] = vertical_intercept(line, x);
323 } else if (verticalType == 2) {
324 fT[0][0] = 0;
325 fT[0][1] = 1;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000326 }
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000327 return fUsed = verticalType;
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000328}
329
330int SkIntersections::vertical(const SkDLine& line, double top, double bottom,
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000331 double x, bool flipped) {
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000332 fMax = 3; // cleanup parallel lines will bring this back line
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000333 // see if end points intersect the opposite line
334 double t;
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000335 SkDPoint topPt = { x, top };
336 if ((t = line.exactPoint(topPt)) >= 0) {
337 insert(t, (double) flipped, topPt);
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000338 }
339 if (top != bottom) {
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000340 SkDPoint bottomPt = { x, bottom };
341 if ((t = line.exactPoint(bottomPt)) >= 0) {
342 insert(t, (double) !flipped, bottomPt);
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000343 }
344 for (int index = 0; index < 2; ++index) {
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000345 if ((t = SkDLine::ExactPointV(line[index], top, bottom, x)) >= 0) {
346 insert((double) index, flipped ? 1 - t : t, line[index]);
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000347 }
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000348 }
349 }
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000350 int result = vertical_coincident(line, x);
351 if (result == 1 && fUsed == 0) {
352 fT[0][0] = vertical_intercept(line, x);
353 double yIntercept = line[0].fY + fT[0][0] * (line[1].fY - line[0].fY);
354 if (between(top, yIntercept, bottom)) {
355 fT[1][0] = (yIntercept - top) / (bottom - top);
356 if (flipped) {
357 // OPTIMIZATION: instead of swapping, pass original line, use [1].fY - [0].fY
358 for (int index = 0; index < result; ++index) {
359 fT[1][index] = 1 - fT[1][index];
360 }
361 }
caryclark@google.com15107262013-11-08 18:00:01 +0000362 fPt[0].fX = x;
363 fPt[0].fY = yIntercept;
364 fUsed = 1;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000365 }
366 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000367 if (fAllowNear || result == 2) {
caryclarkdac1d172014-06-17 05:15:38 -0700368 if ((t = line.nearPoint(topPt, NULL)) >= 0) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000369 insert(t, (double) flipped, topPt);
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000370 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000371 if (top != bottom) {
372 SkDPoint bottomPt = { x, bottom };
caryclarkdac1d172014-06-17 05:15:38 -0700373 if ((t = line.nearPoint(bottomPt, NULL)) >= 0) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000374 insert(t, (double) !flipped, bottomPt);
375 }
376 for (int index = 0; index < 2; ++index) {
377 if ((t = SkDLine::NearPointV(line[index], top, bottom, x)) >= 0) {
378 insert((double) index, flipped ? 1 - t : t, line[index]);
379 }
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000380 }
381 }
382 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000383 cleanUpParallelLines(result == 2);
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +0000384 SkASSERT(fUsed <= 2);
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000385 return fUsed;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000386}
387
388// from http://www.bryceboe.com/wordpress/wp-content/uploads/2006/10/intersect.py
389// 4 subs, 2 muls, 1 cmp
390static bool ccw(const SkDPoint& A, const SkDPoint& B, const SkDPoint& C) {
391 return (C.fY - A.fY) * (B.fX - A.fX) > (B.fY - A.fY) * (C.fX - A.fX);
392}
393
394// 16 subs, 8 muls, 6 cmps
395bool SkIntersections::Test(const SkDLine& a, const SkDLine& b) {
396 return ccw(a[0], b[0], b[1]) != ccw(a[1], b[0], b[1])
397 && ccw(a[0], a[1], b[0]) != ccw(a[0], a[1], b[1]);
398}