Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(182)

Side by Side Diff: src/pathops/SkDLineIntersection.cpp

Issue 18058007: path ops work in progress (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: try try again Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/pathops/SkDCubicLineIntersection.cpp ('k') | src/pathops/SkDQuadLineIntersection.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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, 10 /* Determine the intersection point of two lines. This assumes the lines are not parallel,
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
68 return fUsed = 0; 68 return fUsed = 0;
69 } 69 }
70 // there's no great answer for intersection points for coincident rays, but return something 70 // there's no great answer for intersection points for coincident rays, but return something
71 fT[0][0] = fT[1][0] = 0; 71 fT[0][0] = fT[1][0] = 0;
72 fT[1][0] = fT[1][1] = 1; 72 fT[1][0] = fT[1][1] = 1;
73 used = 2; 73 used = 2;
74 } 74 }
75 return computePoints(a, used); 75 return computePoints(a, used);
76 } 76 }
77 77
78 /* 78 static bool checkEndPoint(double x, double y, const SkDLine& l, double* tPtr, in t useX) {
79 Determine the intersection point of two line segments 79 if (!between(l[0].fX, x, l[1].fX) || !between(l[0].fY, y, l[1].fY)) {
80 Return FALSE if the lines don't intersect 80 return false;
81 from: http://paulbourke.net/geometry/lineline2d/ 81 }
82 */ 82 double xLen = l[1].fX - l[0].fX;
83 double yLen = l[1].fY - l[0].fY;
84 if (useX < 0) {
85 useX = SkTAbs(xLen) > SkTAbs(yLen);
86 }
87 // OPTIMIZATION: do between test before divide
88 double t = useX ? (x - l[0].fX) / xLen : (y - l[0].fY) / yLen;
89 if (!between(0, t, 1)) {
90 return false;
91 }
92 double opp = useX ? (1 - t) * l[0].fY + t * l[1].fY : (1 - t) * l[0].fX + t * l[1].fX;
93 if (!AlmostEqualUlps(opp, useX ? y : x)) {
94 return false;
95 }
96 *tPtr = t;
97 return true;
98 }
83 99
100 // note that this only works if both lines are neither horizontal nor vertical
84 int SkIntersections::intersect(const SkDLine& a, const SkDLine& b) { 101 int SkIntersections::intersect(const SkDLine& a, const SkDLine& b) {
102 // see if end points intersect the opposite line
103 double t;
104 for (int iA = 0; iA < 2; ++iA) {
105 if (!checkEndPoint(a[iA].fX, a[iA].fY, b, &t, -1)) {
106 continue;
107 }
108 insert(iA, t, a[iA]);
109 }
110 for (int iB = 0; iB < 2; ++iB) {
111 if (!checkEndPoint(b[iB].fX, b[iB].fY, a, &t, -1)) {
112 continue;
113 }
114 insert(t, iB, b[iB]);
115 }
116 if (used() > 0) {
117 SkASSERT(fUsed <= 2);
118 return used(); // coincident lines are returned here
119 }
120 /* Determine the intersection point of two line segments
121 Return FALSE if the lines don't intersect
122 from: http://paulbourke.net/geometry/lineline2d/ */
85 double axLen = a[1].fX - a[0].fX; 123 double axLen = a[1].fX - a[0].fX;
86 double ayLen = a[1].fY - a[0].fY; 124 double ayLen = a[1].fY - a[0].fY;
87 double bxLen = b[1].fX - b[0].fX; 125 double bxLen = b[1].fX - b[0].fX;
88 double byLen = b[1].fY - b[0].fY; 126 double byLen = b[1].fY - b[0].fY;
89 /* Slopes match when denom goes to zero: 127 /* Slopes match when denom goes to zero:
90 axLen / ayLen == bxLen / byLen 128 axLen / ayLen == bxLen / byLen
91 (ayLen * byLen) * axLen / ayLen == (ayLen * byLen) * bxLen / byLen 129 (ayLen * byLen) * axLen / ayLen == (ayLen * byLen) * bxLen / byLen
92 byLen * axLen == ayLen * bxLen 130 byLen * axLen == ayLen * bxLen
93 byLen * axLen - ayLen * bxLen == 0 ( == denom ) 131 byLen * axLen - ayLen * bxLen == 0 ( == denom )
94 */ 132 */
95 double denom = byLen * axLen - ayLen * bxLen; 133 double denom = byLen * axLen - ayLen * bxLen;
96 double ab0y = a[0].fY - b[0].fY; 134 double ab0y = a[0].fY - b[0].fY;
97 double ab0x = a[0].fX - b[0].fX; 135 double ab0x = a[0].fX - b[0].fX;
98 double numerA = ab0y * bxLen - byLen * ab0x; 136 double numerA = ab0y * bxLen - byLen * ab0x;
99 double numerB = ab0y * axLen - ayLen * ab0x; 137 double numerB = ab0y * axLen - ayLen * ab0x;
100 bool mayNotOverlap = (numerA < 0 && denom > numerA) || (numerA > 0 && denom < numerA) 138 bool mayNotOverlap = (numerA < 0 && denom > numerA) || (numerA > 0 && denom < numerA)
101 || (numerB < 0 && denom > numerB) || (numerB > 0 && denom < numerB); 139 || (numerB < 0 && denom > numerB) || (numerB > 0 && denom < numerB);
102 numerA /= denom; 140 numerA /= denom;
103 numerB /= denom; 141 numerB /= denom;
104 if ((!approximately_zero(denom) || (!approximately_zero_inverse(numerA) 142 if ((!approximately_zero(denom) || (!approximately_zero_inverse(numerA)
105 && !approximately_zero_inverse(numerB))) && !sk_double_isnan(numerA) 143 && !approximately_zero_inverse(numerB))) && !sk_double_isnan(numerA)
106 && !sk_double_isnan(numerB)) { 144 && !sk_double_isnan(numerB)) {
107 if (mayNotOverlap) { 145 if (mayNotOverlap) {
108 return fUsed = 0; 146 return 0;
109 } 147 }
110 fT[0][0] = numerA; 148 fT[0][0] = numerA;
111 fT[1][0] = numerB; 149 fT[1][0] = numerB;
112 fPt[0] = a.xyAtT(numerA); 150 fPt[0] = a.xyAtT(numerA);
113 return computePoints(a, 1); 151 return computePoints(a, 1);
114 } 152 }
115 /* See if the axis intercepts match: 153 return 0;
116 ay - ax * ayLen / axLen == by - bx * ayLen / axLen
117 axLen * (ay - ax * ayLen / axLen) == axLen * (by - bx * ayLen / axLen)
118 axLen * ay - ax * ayLen == axLen * by - bx * ayLen
119 */
120 if (!AlmostEqualUlps(axLen * a[0].fY - ayLen * a[0].fX,
121 axLen * b[0].fY - ayLen * b[0].fX)) {
122 return fUsed = 0;
123 }
124 const double* aPtr;
125 const double* bPtr;
126 if (fabs(axLen) > fabs(ayLen) || fabs(bxLen) > fabs(byLen)) {
127 aPtr = &a[0].fX;
128 bPtr = &b[0].fX;
129 } else {
130 aPtr = &a[0].fY;
131 bPtr = &b[0].fY;
132 }
133 double a0 = aPtr[0];
134 double a1 = aPtr[2];
135 double b0 = bPtr[0];
136 double b1 = bPtr[2];
137 // OPTIMIZATION: restructure to reject before the divide
138 // e.g., if ((a0 - b0) * (a0 - a1) < 0 || abs(a0 - b0) > abs(a0 - a1))
139 // (except efficient)
140 double aDenom = a0 - a1;
141 if (approximately_zero(aDenom)) {
142 if (!between(b0, a0, b1)) {
143 return fUsed = 0;
144 }
145 fT[0][0] = fT[0][1] = 0;
146 } else {
147 double at0 = (a0 - b0) / aDenom;
148 double at1 = (a0 - b1) / aDenom;
149 if ((at0 < 0 && at1 < 0) || (at0 > 1 && at1 > 1)) {
150 return fUsed = 0;
151 }
152 fT[0][0] = SkTMax(SkTMin(at0, 1.0), 0.0);
153 fT[0][1] = SkTMax(SkTMin(at1, 1.0), 0.0);
154 }
155 double bDenom = b0 - b1;
156 if (approximately_zero(bDenom)) {
157 fT[1][0] = fT[1][1] = 0;
158 } else {
159 int bIn = aDenom * bDenom < 0;
160 fT[1][bIn] = SkTMax(SkTMin((b0 - a0) / bDenom, 1.0), 0.0);
161 fT[1][!bIn] = SkTMax(SkTMin((b0 - a1) / bDenom, 1.0), 0.0);
162 }
163 bool second = fabs(fT[0][0] - fT[0][1]) > FLT_EPSILON;
164 SkASSERT((fabs(fT[1][0] - fT[1][1]) <= FLT_EPSILON) ^ second);
165 return computePoints(a, 1 + second);
166 } 154 }
167 155
168 int SkIntersections::horizontal(const SkDLine& line, double y) { 156 int SkIntersections::horizontal(const SkDLine& line, double y) {
169 double min = line[0].fY; 157 double min = line[0].fY;
170 double max = line[1].fY; 158 double max = line[1].fY;
171 if (min > max) { 159 if (min > max) {
172 SkTSwap(min, max); 160 SkTSwap(min, max);
173 } 161 }
174 if (min > y || max < y) { 162 if (min > y || max < y) {
175 return fUsed = 0; 163 return fUsed = 0;
176 } 164 }
177 if (AlmostEqualUlps(min, max)) { 165 if (AlmostEqualUlps(min, max) && max - min < fabs(line[0].fX - line[1].fX)) {
178 fT[0][0] = 0; 166 fT[0][0] = 0;
179 fT[0][1] = 1; 167 fT[0][1] = 1;
180 return fUsed = 2; 168 return fUsed = 2;
181 } 169 }
182 fT[0][0] = (y - line[0].fY) / (line[1].fY - line[0].fY); 170 fT[0][0] = (y - line[0].fY) / (line[1].fY - line[0].fY);
183 return fUsed = 1; 171 return fUsed = 1;
184 } 172 }
185 173
174 static bool checkEndPointH(const SkDPoint& end, double left, double right,
175 double y, bool flipped, double* tPtr) {
176 if (!between(left, end.fX, right) || !AlmostEqualUlps(y, end.fY)) {
177 return false;
178 }
179 double t = (end.fX - left) / (right - left);
180 SkASSERT(between(0, t, 1));
181 *tPtr = flipped ? 1 - t : t;
182 return true;
183 }
184
186 int SkIntersections::horizontal(const SkDLine& line, double left, double right, 185 int SkIntersections::horizontal(const SkDLine& line, double left, double right,
187 double y, bool flipped) { 186 double y, bool flipped) {
187 // see if end points intersect the opposite line
188 double t;
189 if (checkEndPoint(left, y, line, &t, true)) {
190 insert(t, flipped, left, y);
191 }
192 if (left != right) {
193 if (checkEndPoint(right, y, line, &t, true)) {
194 insert(t, !flipped, right, y);
195 }
196 for (int index = 0; index < 2; ++index) {
197 if (!checkEndPointH(line[index], left, right, y, flipped, &t)) {
198 continue;
199 }
200 insert(index, t, line[index]);
201 }
202 }
203 if (used() > 0) {
204 SkASSERT(fUsed <= 2);
205 return used(); // coincident lines are returned here
206 }
188 int result = horizontal(line, y); 207 int result = horizontal(line, y);
189 switch (result) { 208 if (!result) {
190 case 0: 209 return 0;
191 break;
192 case 1: {
193 double xIntercept = line[0].fX + fT[0][0] * (line[1].fX - line[0].fX );
194 if (!precisely_between(left, xIntercept, right)) {
195 return fUsed = 0;
196 }
197 fT[1][0] = (xIntercept - left) / (right - left);
198 break;
199 }
200 case 2:
201 double a0 = line[0].fX;
202 double a1 = line[1].fX;
203 double b0 = flipped ? right : left;
204 double b1 = flipped ? left : right;
205 // FIXME: share common code below
206 double at0 = (a0 - b0) / (a0 - a1);
207 double at1 = (a0 - b1) / (a0 - a1);
208 if ((at0 < 0 && at1 < 0) || (at0 > 1 && at1 > 1)) {
209 return fUsed = 0;
210 }
211 fT[0][0] = SkTMax(SkTMin(at0, 1.0), 0.0);
212 fT[0][1] = SkTMax(SkTMin(at1, 1.0), 0.0);
213 int bIn = (a0 - a1) * (b0 - b1) < 0;
214 fT[1][bIn] = SkTMax(SkTMin((b0 - a0) / (b0 - b1), 1.0), 0.0);
215 fT[1][!bIn] = SkTMax(SkTMin((b0 - a1) / (b0 - b1), 1.0), 0.0);
216 bool second = fabs(fT[0][0] - fT[0][1]) > FLT_EPSILON;
217 SkASSERT((fabs(fT[1][0] - fT[1][1]) <= FLT_EPSILON) ^ second);
218 return computePoints(line, 1 + second);
219 } 210 }
211 SkASSERT(result == 1);
212 double xIntercept = line[0].fX + fT[0][0] * (line[1].fX - line[0].fX);
213 if (!precisely_between(left, xIntercept, right)) {
214 return fUsed = 0;
215 }
216 fT[1][0] = (xIntercept - left) / (right - left);
220 if (flipped) { 217 if (flipped) {
221 // OPTIMIZATION: instead of swapping, pass original line, use [1].fX - [ 0].fX 218 // OPTIMIZATION: ? instead of swapping, pass original line, use [1].fX - [0].fX
222 for (int index = 0; index < result; ++index) { 219 for (int index = 0; index < result; ++index) {
223 fT[1][index] = 1 - fT[1][index]; 220 fT[1][index] = 1 - fT[1][index];
224 } 221 }
225 } 222 }
226 return computePoints(line, result); 223 return computePoints(line, result);
227 } 224 }
228 225
229 int SkIntersections::vertical(const SkDLine& line, double x) { 226 int SkIntersections::vertical(const SkDLine& line, double x) {
230 double min = line[0].fX; 227 double min = line[0].fX;
231 double max = line[1].fX; 228 double max = line[1].fX;
232 if (min > max) { 229 if (min > max) {
233 SkTSwap(min, max); 230 SkTSwap(min, max);
234 } 231 }
235 if (!precisely_between(min, x, max)) { 232 if (!precisely_between(min, x, max)) {
236 return fUsed = 0; 233 return fUsed = 0;
237 } 234 }
238 if (AlmostEqualUlps(min, max)) { 235 if (AlmostEqualUlps(min, max)) {
239 fT[0][0] = 0; 236 fT[0][0] = 0;
240 fT[0][1] = 1; 237 fT[0][1] = 1;
241 return fUsed = 2; 238 return fUsed = 2;
242 } 239 }
243 fT[0][0] = (x - line[0].fX) / (line[1].fX - line[0].fX); 240 fT[0][0] = (x - line[0].fX) / (line[1].fX - line[0].fX);
244 return fUsed = 1; 241 return fUsed = 1;
245 } 242 }
246 243
244 static bool checkEndPointV(const SkDPoint& end, double top, double bottom,
245 double x, bool flipped, double* tPtr) {
246 if (!between(top, end.fY, bottom) || !AlmostEqualUlps(x, end.fX)) {
247 return false;
248 }
249 double t = (end.fY - top) / (bottom - top);
250 SkASSERT(between(0, t, 1));
251 *tPtr = flipped ? 1 - t : t;
252 return true;
253 }
254
247 int SkIntersections::vertical(const SkDLine& line, double top, double bottom, 255 int SkIntersections::vertical(const SkDLine& line, double top, double bottom,
248 double x, bool flipped) { 256 double x, bool flipped) {
257 // see if end points intersect the opposite line
258 double t;
259 if (checkEndPoint(x, top, line, &t, false)) {
260 insert(t, flipped, x, top);
261 }
262 if (top != bottom) {
263 if (checkEndPoint(x, bottom,line, &t, false)) {
264 insert(t, !flipped, x, bottom);
265 }
266 for (int index = 0; index < 2; ++index) {
267 if (!checkEndPointV(line[index], top, bottom, x, flipped, &t)) {
268 continue;
269 }
270 insert( index, t, line[index]);
271 }
272 }
273 if (used() > 0) {
274 SkASSERT(fUsed <= 2);
275 return used(); // coincident lines are returned here
276 }
249 int result = vertical(line, x); 277 int result = vertical(line, x);
250 switch (result) { 278 if (!result) {
251 case 0: 279 return 0;
252 break;
253 case 1: {
254 double yIntercept = line[0].fY + fT[0][0] * (line[1].fY - line[0].fY );
255 if (!precisely_between(top, yIntercept, bottom)) {
256 return fUsed = 0;
257 }
258 fT[1][0] = (yIntercept - top) / (bottom - top);
259 break;
260 }
261 case 2:
262 double a0 = line[0].fY;
263 double a1 = line[1].fY;
264 double b0 = flipped ? bottom : top;
265 double b1 = flipped ? top : bottom;
266 // FIXME: share common code above
267 double at0 = (a0 - b0) / (a0 - a1);
268 double at1 = (a0 - b1) / (a0 - a1);
269 if ((at0 < 0 && at1 < 0) || (at0 > 1 && at1 > 1)) {
270 return fUsed = 0;
271 }
272 fT[0][0] = SkTMax(SkTMin(at0, 1.0), 0.0);
273 fT[0][1] = SkTMax(SkTMin(at1, 1.0), 0.0);
274 int bIn = (a0 - a1) * (b0 - b1) < 0;
275 fT[1][bIn] = SkTMax(SkTMin((b0 - a0) / (b0 - b1), 1.0), 0.0);
276 fT[1][!bIn] = SkTMax(SkTMin((b0 - a1) / (b0 - b1), 1.0), 0.0);
277 bool second = fabs(fT[0][0] - fT[0][1]) > FLT_EPSILON;
278 SkASSERT((fabs(fT[1][0] - fT[1][1]) <= FLT_EPSILON) ^ second);
279 return computePoints(line, 1 + second);
280 } 280 }
281 SkASSERT(result == 1);
282 double yIntercept = line[0].fY + fT[0][0] * (line[1].fY - line[0].fY);
283 if (!precisely_between(top, yIntercept, bottom)) {
284 return fUsed = 0;
285 }
286 fT[1][0] = (yIntercept - top) / (bottom - top);
281 if (flipped) { 287 if (flipped) {
282 // OPTIMIZATION: instead of swapping, pass original line, use [1].fY - [ 0].fY 288 // OPTIMIZATION: instead of swapping, pass original line, use [1].fY - [ 0].fY
283 for (int index = 0; index < result; ++index) { 289 for (int index = 0; index < result; ++index) {
284 fT[1][index] = 1 - fT[1][index]; 290 fT[1][index] = 1 - fT[1][index];
285 } 291 }
286 } 292 }
287 return computePoints(line, result); 293 return computePoints(line, result);
288 } 294 }
289 295
290 // from http://www.bryceboe.com/wordpress/wp-content/uploads/2006/10/intersect.p y 296 // from http://www.bryceboe.com/wordpress/wp-content/uploads/2006/10/intersect.p y
291 // 4 subs, 2 muls, 1 cmp 297 // 4 subs, 2 muls, 1 cmp
292 static bool ccw(const SkDPoint& A, const SkDPoint& B, const SkDPoint& C) { 298 static bool ccw(const SkDPoint& A, const SkDPoint& B, const SkDPoint& C) {
293 return (C.fY - A.fY) * (B.fX - A.fX) > (B.fY - A.fY) * (C.fX - A.fX); 299 return (C.fY - A.fY) * (B.fX - A.fX) > (B.fY - A.fY) * (C.fX - A.fX);
294 } 300 }
295 301
296 // 16 subs, 8 muls, 6 cmps 302 // 16 subs, 8 muls, 6 cmps
297 bool SkIntersections::Test(const SkDLine& a, const SkDLine& b) { 303 bool SkIntersections::Test(const SkDLine& a, const SkDLine& b) {
298 return ccw(a[0], b[0], b[1]) != ccw(a[1], b[0], b[1]) 304 return ccw(a[0], b[0], b[1]) != ccw(a[1], b[0], b[1])
299 && ccw(a[0], a[1], b[0]) != ccw(a[0], a[1], b[1]); 305 && ccw(a[0], a[1], b[0]) != ccw(a[0], a[1], b[1]);
300 } 306 }
OLDNEW
« no previous file with comments | « src/pathops/SkDCubicLineIntersection.cpp ('k') | src/pathops/SkDQuadLineIntersection.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698