OLD | NEW |
| (Empty) |
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 "CurveIntersection.h" | |
8 #include "Intersections.h" | |
9 #include "LineIntersection.h" | |
10 #include "LineUtilities.h" | |
11 | |
12 /* Determine the intersection point of two lines. This assumes the lines are not
parallel, | |
13 and that that the lines are infinite. | |
14 From http://en.wikipedia.org/wiki/Line-line_intersection | |
15 */ | |
16 void lineIntersect(const _Line& a, const _Line& b, _Point& p) { | |
17 double axLen = a[1].x - a[0].x; | |
18 double ayLen = a[1].y - a[0].y; | |
19 double bxLen = b[1].x - b[0].x; | |
20 double byLen = b[1].y - b[0].y; | |
21 double denom = byLen * axLen - ayLen * bxLen; | |
22 SkASSERT(denom); | |
23 double term1 = a[1].x * a[0].y - a[1].y * a[0].x; | |
24 double term2 = b[1].x * b[0].y - b[1].y * b[0].x; | |
25 p.x = (term1 * bxLen - axLen * term2) / denom; | |
26 p.y = (term1 * byLen - ayLen * term2) / denom; | |
27 } | |
28 | |
29 static int computePoints(const _Line& a, int used, Intersections& i) { | |
30 i.fPt[0] = xy_at_t(a, i.fT[0][0]); | |
31 if ((i.fUsed = used) == 2) { | |
32 i.fPt[1] = xy_at_t(a, i.fT[0][1]); | |
33 } | |
34 return i.fUsed; | |
35 } | |
36 | |
37 /* | |
38 Determine the intersection point of two line segments | |
39 Return FALSE if the lines don't intersect | |
40 from: http://paulbourke.net/geometry/lineline2d/ | |
41 */ | |
42 | |
43 int intersect(const _Line& a, const _Line& b, Intersections& i) { | |
44 double axLen = a[1].x - a[0].x; | |
45 double ayLen = a[1].y - a[0].y; | |
46 double bxLen = b[1].x - b[0].x; | |
47 double byLen = b[1].y - b[0].y; | |
48 /* Slopes match when denom goes to zero: | |
49 axLen / ayLen == bxLen / byLen | |
50 (ayLen * byLen) * axLen / ayLen == (ayLen * byLen) * bxLen / byLen | |
51 byLen * axLen == ayLen * bxLen | |
52 byLen * axLen - ayLen * bxLen == 0 ( == denom ) | |
53 */ | |
54 double denom = byLen * axLen - ayLen * bxLen; | |
55 double ab0y = a[0].y - b[0].y; | |
56 double ab0x = a[0].x - b[0].x; | |
57 double numerA = ab0y * bxLen - byLen * ab0x; | |
58 double numerB = ab0y * axLen - ayLen * ab0x; | |
59 bool mayNotOverlap = (numerA < 0 && denom > numerA) || (numerA > 0 && denom
< numerA) | |
60 || (numerB < 0 && denom > numerB) || (numerB > 0 && denom < numerB); | |
61 numerA /= denom; | |
62 numerB /= denom; | |
63 if ((!approximately_zero(denom) || (!approximately_zero_inverse(numerA) | |
64 && !approximately_zero_inverse(numerB))) && !sk_double_isnan(numerA) | |
65 && !sk_double_isnan(numerB)) { | |
66 if (mayNotOverlap) { | |
67 return 0; | |
68 } | |
69 i.fT[0][0] = numerA; | |
70 i.fT[1][0] = numerB; | |
71 i.fPt[0] = xy_at_t(a, numerA); | |
72 return computePoints(a, 1, i); | |
73 } | |
74 /* See if the axis intercepts match: | |
75 ay - ax * ayLen / axLen == by - bx * ayLen / axLen | |
76 axLen * (ay - ax * ayLen / axLen) == axLen * (by - bx * ayLen / axLen) | |
77 axLen * ay - ax * ayLen == axLen * by - bx * ayLen | |
78 */ | |
79 // FIXME: need to use AlmostEqualUlps variant instead | |
80 if (!approximately_equal_squared(axLen * a[0].y - ayLen * a[0].x, | |
81 axLen * b[0].y - ayLen * b[0].x)) { | |
82 return 0; | |
83 } | |
84 const double* aPtr; | |
85 const double* bPtr; | |
86 if (fabs(axLen) > fabs(ayLen) || fabs(bxLen) > fabs(byLen)) { | |
87 aPtr = &a[0].x; | |
88 bPtr = &b[0].x; | |
89 } else { | |
90 aPtr = &a[0].y; | |
91 bPtr = &b[0].y; | |
92 } | |
93 double a0 = aPtr[0]; | |
94 double a1 = aPtr[2]; | |
95 double b0 = bPtr[0]; | |
96 double b1 = bPtr[2]; | |
97 // OPTIMIZATION: restructure to reject before the divide | |
98 // e.g., if ((a0 - b0) * (a0 - a1) < 0 || abs(a0 - b0) > abs(a0 - a1)) | |
99 // (except efficient) | |
100 double aDenom = a0 - a1; | |
101 if (approximately_zero(aDenom)) { | |
102 if (!between(b0, a0, b1)) { | |
103 return 0; | |
104 } | |
105 i.fT[0][0] = i.fT[0][1] = 0; | |
106 } else { | |
107 double at0 = (a0 - b0) / aDenom; | |
108 double at1 = (a0 - b1) / aDenom; | |
109 if ((at0 < 0 && at1 < 0) || (at0 > 1 && at1 > 1)) { | |
110 return 0; | |
111 } | |
112 i.fT[0][0] = SkTMax(SkTMin(at0, 1.0), 0.0); | |
113 i.fT[0][1] = SkTMax(SkTMin(at1, 1.0), 0.0); | |
114 } | |
115 double bDenom = b0 - b1; | |
116 if (approximately_zero(bDenom)) { | |
117 i.fT[1][0] = i.fT[1][1] = 0; | |
118 } else { | |
119 int bIn = aDenom * bDenom < 0; | |
120 i.fT[1][bIn] = SkTMax(SkTMin((b0 - a0) / bDenom, 1.0), 0.0); | |
121 i.fT[1][!bIn] = SkTMax(SkTMin((b0 - a1) / bDenom, 1.0), 0.0); | |
122 } | |
123 bool second = fabs(i.fT[0][0] - i.fT[0][1]) > FLT_EPSILON; | |
124 SkASSERT((fabs(i.fT[1][0] - i.fT[1][1]) <= FLT_EPSILON) ^ second); | |
125 return computePoints(a, 1 + second, i); | |
126 } | |
127 | |
128 int horizontalIntersect(const _Line& line, double y, double tRange[2]) { | |
129 double min = line[0].y; | |
130 double max = line[1].y; | |
131 if (min > max) { | |
132 SkTSwap(min, max); | |
133 } | |
134 if (min > y || max < y) { | |
135 return 0; | |
136 } | |
137 if (AlmostEqualUlps(min, max)) { | |
138 tRange[0] = 0; | |
139 tRange[1] = 1; | |
140 return 2; | |
141 } | |
142 tRange[0] = (y - line[0].y) / (line[1].y - line[0].y); | |
143 return 1; | |
144 } | |
145 | |
146 // OPTIMIZATION Given: dy = line[1].y - line[0].y | |
147 // and: xIntercept / (y - line[0].y) == (line[1].x - line[0].x) / dy | |
148 // then: xIntercept * dy == (line[1].x - line[0].x) * (y - line[0].y) | |
149 // Assuming that dy is always > 0, the line segment intercepts if: | |
150 // left * dy <= xIntercept * dy <= right * dy | |
151 // thus: left * dy <= (line[1].x - line[0].x) * (y - line[0].y) <= right * dy | |
152 // (clever as this is, it does not give us the t value, so may be useful only | |
153 // as a quick reject -- and maybe not then; it takes 3 muls, 3 adds, 2 cmps) | |
154 int horizontalLineIntersect(const _Line& line, double left, double right, | |
155 double y, double tRange[2]) { | |
156 int result = horizontalIntersect(line, y, tRange); | |
157 if (result != 1) { | |
158 // FIXME: this is incorrect if result == 2 | |
159 return result; | |
160 } | |
161 double xIntercept = line[0].x + tRange[0] * (line[1].x - line[0].x); | |
162 if (xIntercept > right || xIntercept < left) { | |
163 return 0; | |
164 } | |
165 return result; | |
166 } | |
167 | |
168 int horizontalIntersect(const _Line& line, double left, double right, | |
169 double y, bool flipped, Intersections& intersections) { | |
170 int result = horizontalIntersect(line, y, intersections.fT[0]); | |
171 switch (result) { | |
172 case 0: | |
173 break; | |
174 case 1: { | |
175 double xIntercept = line[0].x + intersections.fT[0][0] | |
176 * (line[1].x - line[0].x); | |
177 if (xIntercept > right || xIntercept < left) { | |
178 return 0; | |
179 } | |
180 intersections.fT[1][0] = (xIntercept - left) / (right - left); | |
181 break; | |
182 } | |
183 case 2: | |
184 #if 0 // sorting edges fails to preserve original direction | |
185 double lineL = line[0].x; | |
186 double lineR = line[1].x; | |
187 if (lineL > lineR) { | |
188 SkTSwap(lineL, lineR); | |
189 } | |
190 double overlapL = SkTMax(left, lineL); | |
191 double overlapR = SkTMin(right, lineR); | |
192 if (overlapL > overlapR) { | |
193 return 0; | |
194 } | |
195 if (overlapL == overlapR) { | |
196 result = 1; | |
197 } | |
198 intersections.fT[0][0] = (overlapL - line[0].x) / (line[1].x - line[
0].x); | |
199 intersections.fT[1][0] = (overlapL - left) / (right - left); | |
200 if (result > 1) { | |
201 intersections.fT[0][1] = (overlapR - line[0].x) / (line[1].x - l
ine[0].x); | |
202 intersections.fT[1][1] = (overlapR - left) / (right - left); | |
203 } | |
204 #else | |
205 double a0 = line[0].x; | |
206 double a1 = line[1].x; | |
207 double b0 = flipped ? right : left; | |
208 double b1 = flipped ? left : right; | |
209 // FIXME: share common code below | |
210 double at0 = (a0 - b0) / (a0 - a1); | |
211 double at1 = (a0 - b1) / (a0 - a1); | |
212 if ((at0 < 0 && at1 < 0) || (at0 > 1 && at1 > 1)) { | |
213 return 0; | |
214 } | |
215 intersections.fT[0][0] = SkTMax(SkTMin(at0, 1.0), 0.0); | |
216 intersections.fT[0][1] = SkTMax(SkTMin(at1, 1.0), 0.0); | |
217 int bIn = (a0 - a1) * (b0 - b1) < 0; | |
218 intersections.fT[1][bIn] = SkTMax(SkTMin((b0 - a0) / (b0 - b1), | |
219 1.0), 0.0); | |
220 intersections.fT[1][!bIn] = SkTMax(SkTMin((b0 - a1) / (b0 - b1), | |
221 1.0), 0.0); | |
222 bool second = fabs(intersections.fT[0][0] - intersections.fT[0][1]) | |
223 > FLT_EPSILON; | |
224 SkASSERT((fabs(intersections.fT[1][0] - intersections.fT[1][1]) | |
225 <= FLT_EPSILON) ^ second); | |
226 return computePoints(line, 1 + second, intersections); | |
227 #endif | |
228 break; | |
229 } | |
230 if (flipped) { | |
231 // OPTIMIZATION: instead of swapping, pass original line, use [1].x - [0
].x | |
232 for (int index = 0; index < result; ++index) { | |
233 intersections.fT[1][index] = 1 - intersections.fT[1][index]; | |
234 } | |
235 } | |
236 return computePoints(line, result, intersections); | |
237 } | |
238 | |
239 static int verticalIntersect(const _Line& line, double x, double tRange[2]) { | |
240 double min = line[0].x; | |
241 double max = line[1].x; | |
242 if (min > max) { | |
243 SkTSwap(min, max); | |
244 } | |
245 if (min > x || max < x) { | |
246 return 0; | |
247 } | |
248 if (AlmostEqualUlps(min, max)) { | |
249 tRange[0] = 0; | |
250 tRange[1] = 1; | |
251 return 2; | |
252 } | |
253 tRange[0] = (x - line[0].x) / (line[1].x - line[0].x); | |
254 return 1; | |
255 } | |
256 | |
257 int verticalIntersect(const _Line& line, double top, double bottom, | |
258 double x, bool flipped, Intersections& intersections) { | |
259 int result = verticalIntersect(line, x, intersections.fT[0]); | |
260 switch (result) { | |
261 case 0: | |
262 break; | |
263 case 1: { | |
264 double yIntercept = line[0].y + intersections.fT[0][0] | |
265 * (line[1].y - line[0].y); | |
266 if (yIntercept > bottom || yIntercept < top) { | |
267 return 0; | |
268 } | |
269 intersections.fT[1][0] = (yIntercept - top) / (bottom - top); | |
270 break; | |
271 } | |
272 case 2: | |
273 #if 0 // sorting edges fails to preserve original direction | |
274 double lineT = line[0].y; | |
275 double lineB = line[1].y; | |
276 if (lineT > lineB) { | |
277 SkTSwap(lineT, lineB); | |
278 } | |
279 double overlapT = SkTMax(top, lineT); | |
280 double overlapB = SkTMin(bottom, lineB); | |
281 if (overlapT > overlapB) { | |
282 return 0; | |
283 } | |
284 if (overlapT == overlapB) { | |
285 result = 1; | |
286 } | |
287 intersections.fT[0][0] = (overlapT - line[0].y) / (line[1].y - line[
0].y); | |
288 intersections.fT[1][0] = (overlapT - top) / (bottom - top); | |
289 if (result > 1) { | |
290 intersections.fT[0][1] = (overlapB - line[0].y) / (line[1].y - l
ine[0].y); | |
291 intersections.fT[1][1] = (overlapB - top) / (bottom - top); | |
292 } | |
293 #else | |
294 double a0 = line[0].y; | |
295 double a1 = line[1].y; | |
296 double b0 = flipped ? bottom : top; | |
297 double b1 = flipped ? top : bottom; | |
298 // FIXME: share common code above | |
299 double at0 = (a0 - b0) / (a0 - a1); | |
300 double at1 = (a0 - b1) / (a0 - a1); | |
301 if ((at0 < 0 && at1 < 0) || (at0 > 1 && at1 > 1)) { | |
302 return 0; | |
303 } | |
304 intersections.fT[0][0] = SkTMax(SkTMin(at0, 1.0), 0.0); | |
305 intersections.fT[0][1] = SkTMax(SkTMin(at1, 1.0), 0.0); | |
306 int bIn = (a0 - a1) * (b0 - b1) < 0; | |
307 intersections.fT[1][bIn] = SkTMax(SkTMin((b0 - a0) / (b0 - b1), | |
308 1.0), 0.0); | |
309 intersections.fT[1][!bIn] = SkTMax(SkTMin((b0 - a1) / (b0 - b1), | |
310 1.0), 0.0); | |
311 bool second = fabs(intersections.fT[0][0] - intersections.fT[0][1]) | |
312 > FLT_EPSILON; | |
313 SkASSERT((fabs(intersections.fT[1][0] - intersections.fT[1][1]) | |
314 <= FLT_EPSILON) ^ second); | |
315 return computePoints(line, 1 + second, intersections); | |
316 #endif | |
317 break; | |
318 } | |
319 if (flipped) { | |
320 // OPTIMIZATION: instead of swapping, pass original line, use [1].y - [0
].y | |
321 for (int index = 0; index < result; ++index) { | |
322 intersections.fT[1][index] = 1 - intersections.fT[1][index]; | |
323 } | |
324 } | |
325 return computePoints(line, result, intersections); | |
326 } | |
327 | |
328 // from http://www.bryceboe.com/wordpress/wp-content/uploads/2006/10/intersect.p
y | |
329 // 4 subs, 2 muls, 1 cmp | |
330 static bool ccw(const _Point& A, const _Point& B, const _Point& C) { | |
331 return (C.y - A.y) * (B.x - A.x) > (B.y - A.y) * (C.x - A.x); | |
332 } | |
333 | |
334 // 16 subs, 8 muls, 6 cmps | |
335 bool testIntersect(const _Line& a, const _Line& b) { | |
336 return ccw(a[0], b[0], b[1]) != ccw(a[1], b[0], b[1]) | |
337 && ccw(a[0], a[1], b[0]) != ccw(a[0], a[1], b[1]); | |
338 } | |
OLD | NEW |