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

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

Issue 19183003: path ops near exact (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: remove unused static function 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/SkDQuadIntersection.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 static bool checkEndPoint(double x, double y, const SkDLine& l, double* tPtr, in t useX) {
79 if (!between(l[0].fX, x, l[1].fX) || !between(l[0].fY, y, l[1].fY)) {
80 return false;
81 }
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 }
99
100 // note that this only works if both lines are neither horizontal nor vertical 78 // note that this only works if both lines are neither horizontal nor vertical
101 int SkIntersections::intersect(const SkDLine& a, const SkDLine& b) { 79 int SkIntersections::intersect(const SkDLine& a, const SkDLine& b) {
102 // see if end points intersect the opposite line 80 // see if end points intersect the opposite line
103 double t; 81 double t;
104 for (int iA = 0; iA < 2; ++iA) { 82 for (int iA = 0; iA < 2; ++iA) {
105 if (!checkEndPoint(a[iA].fX, a[iA].fY, b, &t, -1)) { 83 if ((t = b.exactPoint(a[iA])) >= 0) {
106 continue; 84 insert(iA, t, a[iA]);
107 } 85 }
108 insert(iA, t, a[iA]);
109 } 86 }
110 for (int iB = 0; iB < 2; ++iB) { 87 for (int iB = 0; iB < 2; ++iB) {
111 if (!checkEndPoint(b[iB].fX, b[iB].fY, a, &t, -1)) { 88 if ((t = a.exactPoint(b[iB])) >= 0) {
112 continue; 89 insert(t, iB, b[iB]);
113 } 90 }
114 insert(t, iB, b[iB]);
115 }
116 if (used() > 0) {
117 SkASSERT(fUsed <= 2);
118 return used(); // coincident lines are returned here
119 } 91 }
120 /* Determine the intersection point of two line segments 92 /* Determine the intersection point of two line segments
121 Return FALSE if the lines don't intersect 93 Return FALSE if the lines don't intersect
122 from: http://paulbourke.net/geometry/lineline2d/ */ 94 from: http://paulbourke.net/geometry/lineline2d/ */
123 double axLen = a[1].fX - a[0].fX; 95 double axLen = a[1].fX - a[0].fX;
124 double ayLen = a[1].fY - a[0].fY; 96 double ayLen = a[1].fY - a[0].fY;
125 double bxLen = b[1].fX - b[0].fX; 97 double bxLen = b[1].fX - b[0].fX;
126 double byLen = b[1].fY - b[0].fY; 98 double byLen = b[1].fY - b[0].fY;
127 /* Slopes match when denom goes to zero: 99 /* Slopes match when denom goes to zero:
128 axLen / ayLen == bxLen / byLen 100 axLen / ayLen == bxLen / byLen
129 (ayLen * byLen) * axLen / ayLen == (ayLen * byLen) * bxLen / byLen 101 (ayLen * byLen) * axLen / ayLen == (ayLen * byLen) * bxLen / byLen
130 byLen * axLen == ayLen * bxLen 102 byLen * axLen == ayLen * bxLen
131 byLen * axLen - ayLen * bxLen == 0 ( == denom ) 103 byLen * axLen - ayLen * bxLen == 0 ( == denom )
132 */ 104 */
133 double denom = byLen * axLen - ayLen * bxLen; 105 double denom = byLen * axLen - ayLen * bxLen;
134 double ab0y = a[0].fY - b[0].fY; 106 if (0 != denom) {
135 double ab0x = a[0].fX - b[0].fX; 107 double ab0y = a[0].fY - b[0].fY;
136 double numerA = ab0y * bxLen - byLen * ab0x; 108 double ab0x = a[0].fX - b[0].fX;
137 double numerB = ab0y * axLen - ayLen * ab0x; 109 double numerA = ab0y * bxLen - byLen * ab0x;
138 bool mayNotOverlap = (numerA < 0 && denom > numerA) || (numerA > 0 && denom < numerA) 110 double numerB = ab0y * axLen - ayLen * ab0x;
139 || (numerB < 0 && denom > numerB) || (numerB > 0 && denom < numerB); 111 if (between(0, numerA, denom) && between(0, numerB, denom)) {
140 numerA /= denom; 112 fT[0][0] = numerA / denom;
141 numerB /= denom; 113 fT[1][0] = numerB / denom;
142 if ((!approximately_zero(denom) || (!approximately_zero_inverse(numerA) 114 return computePoints(a, 1);
143 && !approximately_zero_inverse(numerB))) && !sk_double_isnan(numerA)
144 && !sk_double_isnan(numerB)) {
145 if (mayNotOverlap) {
146 return 0;
147 } 115 }
148 fT[0][0] = numerA;
149 fT[1][0] = numerB;
150 fPt[0] = a.xyAtT(numerA);
151 return computePoints(a, 1);
152 } 116 }
153 return 0; 117 if (fAllowNear || 0 == denom) {
118 for (int iA = 0; iA < 2; ++iA) {
119 if ((t = b.nearPoint(a[iA])) >= 0) {
120 insert(iA, t, a[iA]);
121 }
122 }
123 for (int iB = 0; iB < 2; ++iB) {
124 if ((t = a.nearPoint(b[iB])) >= 0) {
125 insert(t, iB, b[iB]);
126 }
127 }
128 }
129 return fUsed;
154 } 130 }
155 131
156 int SkIntersections::horizontal(const SkDLine& line, double y) { 132 static int horizontal_coincident(const SkDLine& line, double y) {
157 double min = line[0].fY; 133 double min = line[0].fY;
158 double max = line[1].fY; 134 double max = line[1].fY;
159 if (min > max) { 135 if (min > max) {
160 SkTSwap(min, max); 136 SkTSwap(min, max);
161 } 137 }
162 if (min > y || max < y) { 138 if (min > y || max < y) {
163 return fUsed = 0; 139 return 0;
164 } 140 }
165 if (AlmostEqualUlps(min, max) && max - min < fabs(line[0].fX - line[1].fX)) { 141 if (AlmostEqualUlps(min, max) && max - min < fabs(line[0].fX - line[1].fX)) {
142 return 2;
143 }
144 return 1;
145 }
146
147 static double horizontal_intercept(const SkDLine& line, double y) {
148 return (y - line[0].fY) / (line[1].fY - line[0].fY);
149 }
150
151 int SkIntersections::horizontal(const SkDLine& line, double y) {
152 int horizontalType = horizontal_coincident(line, y);
153 if (horizontalType == 1) {
154 fT[0][0] = horizontal_intercept(line, y);
155 } else if (horizontalType == 2) {
166 fT[0][0] = 0; 156 fT[0][0] = 0;
167 fT[0][1] = 1; 157 fT[0][1] = 1;
168 return fUsed = 2;
169 } 158 }
170 fT[0][0] = (y - line[0].fY) / (line[1].fY - line[0].fY); 159 return fUsed = horizontalType;
171 return fUsed = 1;
172 }
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 } 160 }
184 161
185 int SkIntersections::horizontal(const SkDLine& line, double left, double right, 162 int SkIntersections::horizontal(const SkDLine& line, double left, double right,
186 double y, bool flipped) { 163 double y, bool flipped) {
187 // see if end points intersect the opposite line 164 // see if end points intersect the opposite line
188 double t; 165 double t;
189 if (checkEndPoint(left, y, line, &t, true)) { 166 const SkDPoint leftPt = { left, y };
190 insert(t, flipped, left, y); 167 if ((t = line.exactPoint(leftPt)) >= 0) {
168 insert(t, (double) flipped, leftPt);
191 } 169 }
192 if (left != right) { 170 if (left != right) {
193 if (checkEndPoint(right, y, line, &t, true)) { 171 const SkDPoint rightPt = { right, y };
194 insert(t, !flipped, right, y); 172 if ((t = line.exactPoint(rightPt)) >= 0) {
173 insert(t, (double) !flipped, rightPt);
195 } 174 }
196 for (int index = 0; index < 2; ++index) { 175 for (int index = 0; index < 2; ++index) {
197 if (!checkEndPointH(line[index], left, right, y, flipped, &t)) { 176 if ((t = SkDLine::ExactPointH(line[index], left, right, y)) >= 0) {
198 continue; 177 insert((double) index, flipped ? 1 - t : t, line[index]);
199 } 178 }
200 insert(index, t, line[index]);
201 } 179 }
202 } 180 }
203 if (used() > 0) { 181 int result = horizontal_coincident(line, y);
204 SkASSERT(fUsed <= 2); 182 if (result == 1 && fUsed == 0) {
205 return used(); // coincident lines are returned here 183 fT[0][0] = horizontal_intercept(line, y);
206 } 184 double xIntercept = line[0].fX + fT[0][0] * (line[1].fX - line[0].fX);
207 int result = horizontal(line, y); 185 if (between(left, xIntercept, right)) {
208 if (!result) { 186 fT[1][0] = (xIntercept - left) / (right - left);
209 return 0; 187 if (flipped) {
210 } 188 // OPTIMIZATION: ? instead of swapping, pass original line, use [1].fX - [0].fX
211 SkASSERT(result == 1); 189 for (int index = 0; index < result; ++index) {
212 double xIntercept = line[0].fX + fT[0][0] * (line[1].fX - line[0].fX); 190 fT[1][index] = 1 - fT[1][index];
213 if (!precisely_between(left, xIntercept, right)) { 191 }
214 return fUsed = 0; 192 }
215 } 193 return computePoints(line, result);
216 fT[1][0] = (xIntercept - left) / (right - left);
217 if (flipped) {
218 // OPTIMIZATION: ? instead of swapping, pass original line, use [1].fX - [0].fX
219 for (int index = 0; index < result; ++index) {
220 fT[1][index] = 1 - fT[1][index];
221 } 194 }
222 } 195 }
223 return computePoints(line, result); 196 if (!fAllowNear && result != 2) {
197 return fUsed;
198 }
199 if ((t = line.nearPoint(leftPt)) >= 0) {
200 insert(t, (double) flipped, leftPt);
201 }
202 if (left != right) {
203 const SkDPoint rightPt = { right, y };
204 if ((t = line.nearPoint(rightPt)) >= 0) {
205 insert(t, (double) !flipped, rightPt);
206 }
207 for (int index = 0; index < 2; ++index) {
208 if ((t = SkDLine::NearPointH(line[index], left, right, y)) >= 0) {
209 insert((double) index, flipped ? 1 - t : t, line[index]);
210 }
211 }
212 }
213 return fUsed;
224 } 214 }
225 215
226 int SkIntersections::vertical(const SkDLine& line, double x) { 216 static int vertical_coincident(const SkDLine& line, double x) {
227 double min = line[0].fX; 217 double min = line[0].fX;
228 double max = line[1].fX; 218 double max = line[1].fX;
229 if (min > max) { 219 if (min > max) {
230 SkTSwap(min, max); 220 SkTSwap(min, max);
231 } 221 }
232 if (!precisely_between(min, x, max)) { 222 if (!precisely_between(min, x, max)) {
233 return fUsed = 0; 223 return 0;
234 } 224 }
235 if (AlmostEqualUlps(min, max)) { 225 if (AlmostEqualUlps(min, max)) {
226 return 2;
227 }
228 return 1;
229 }
230
231 static double vertical_intercept(const SkDLine& line, double x) {
232 return (x - line[0].fX) / (line[1].fX - line[0].fX);
233 }
234
235 int SkIntersections::vertical(const SkDLine& line, double x) {
236 int verticalType = vertical_coincident(line, x);
237 if (verticalType == 1) {
238 fT[0][0] = vertical_intercept(line, x);
239 } else if (verticalType == 2) {
236 fT[0][0] = 0; 240 fT[0][0] = 0;
237 fT[0][1] = 1; 241 fT[0][1] = 1;
238 return fUsed = 2;
239 } 242 }
240 fT[0][0] = (x - line[0].fX) / (line[1].fX - line[0].fX); 243 return fUsed = verticalType;
241 return fUsed = 1;
242 }
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 } 244 }
254 245
255 int SkIntersections::vertical(const SkDLine& line, double top, double bottom, 246 int SkIntersections::vertical(const SkDLine& line, double top, double bottom,
256 double x, bool flipped) { 247 double x, bool flipped) {
257 // see if end points intersect the opposite line 248 // see if end points intersect the opposite line
258 double t; 249 double t;
259 if (checkEndPoint(x, top, line, &t, false)) { 250 SkDPoint topPt = { x, top };
260 insert(t, flipped, x, top); 251 if ((t = line.exactPoint(topPt)) >= 0) {
252 insert(t, (double) flipped, topPt);
261 } 253 }
262 if (top != bottom) { 254 if (top != bottom) {
263 if (checkEndPoint(x, bottom,line, &t, false)) { 255 SkDPoint bottomPt = { x, bottom };
264 insert(t, !flipped, x, bottom); 256 if ((t = line.exactPoint(bottomPt)) >= 0) {
257 insert(t, (double) !flipped, bottomPt);
265 } 258 }
266 for (int index = 0; index < 2; ++index) { 259 for (int index = 0; index < 2; ++index) {
267 if (!checkEndPointV(line[index], top, bottom, x, flipped, &t)) { 260 if ((t = SkDLine::ExactPointV(line[index], top, bottom, x)) >= 0) {
268 continue; 261 insert((double) index, flipped ? 1 - t : t, line[index]);
269 } 262 }
270 insert( index, t, line[index]);
271 } 263 }
272 } 264 }
273 if (used() > 0) { 265 int result = vertical_coincident(line, x);
274 SkASSERT(fUsed <= 2); 266 if (result == 1 && fUsed == 0) {
275 return used(); // coincident lines are returned here 267 fT[0][0] = vertical_intercept(line, x);
276 } 268 double yIntercept = line[0].fY + fT[0][0] * (line[1].fY - line[0].fY);
277 int result = vertical(line, x); 269 if (between(top, yIntercept, bottom)) {
278 if (!result) { 270 fT[1][0] = (yIntercept - top) / (bottom - top);
279 return 0; 271 if (flipped) {
280 } 272 // OPTIMIZATION: instead of swapping, pass original line, use [1 ].fY - [0].fY
281 SkASSERT(result == 1); 273 for (int index = 0; index < result; ++index) {
282 double yIntercept = line[0].fY + fT[0][0] * (line[1].fY - line[0].fY); 274 fT[1][index] = 1 - fT[1][index];
283 if (!precisely_between(top, yIntercept, bottom)) { 275 }
284 return fUsed = 0; 276 }
285 } 277 return computePoints(line, result);
286 fT[1][0] = (yIntercept - top) / (bottom - top);
287 if (flipped) {
288 // OPTIMIZATION: instead of swapping, pass original line, use [1].fY - [ 0].fY
289 for (int index = 0; index < result; ++index) {
290 fT[1][index] = 1 - fT[1][index];
291 } 278 }
292 } 279 }
293 return computePoints(line, result); 280 if (!fAllowNear && result != 2) {
281 return fUsed;
282 }
283 if ((t = line.nearPoint(topPt)) >= 0) {
284 insert(t, (double) flipped, topPt);
285 }
286 if (top != bottom) {
287 SkDPoint bottomPt = { x, bottom };
288 if ((t = line.nearPoint(bottomPt)) >= 0) {
289 insert(t, (double) !flipped, bottomPt);
290 }
291 for (int index = 0; index < 2; ++index) {
292 if ((t = SkDLine::NearPointV(line[index], top, bottom, x)) >= 0) {
293 insert((double) index, flipped ? 1 - t : t, line[index]);
294 }
295 }
296 }
297 return fUsed;
294 } 298 }
295 299
296 // from http://www.bryceboe.com/wordpress/wp-content/uploads/2006/10/intersect.p y 300 // from http://www.bryceboe.com/wordpress/wp-content/uploads/2006/10/intersect.p y
297 // 4 subs, 2 muls, 1 cmp 301 // 4 subs, 2 muls, 1 cmp
298 static bool ccw(const SkDPoint& A, const SkDPoint& B, const SkDPoint& C) { 302 static bool ccw(const SkDPoint& A, const SkDPoint& B, const SkDPoint& C) {
299 return (C.fY - A.fY) * (B.fX - A.fX) > (B.fY - A.fY) * (C.fX - A.fX); 303 return (C.fY - A.fY) * (B.fX - A.fX) > (B.fY - A.fY) * (C.fX - A.fX);
300 } 304 }
301 305
302 // 16 subs, 8 muls, 6 cmps 306 // 16 subs, 8 muls, 6 cmps
303 bool SkIntersections::Test(const SkDLine& a, const SkDLine& b) { 307 bool SkIntersections::Test(const SkDLine& a, const SkDLine& b) {
304 return ccw(a[0], b[0], b[1]) != ccw(a[1], b[0], b[1]) 308 return ccw(a[0], b[0], b[1]) != ccw(a[1], b[0], b[1])
305 && ccw(a[0], a[1], b[0]) != ccw(a[0], a[1], b[1]); 309 && ccw(a[0], a[1], b[0]) != ccw(a[0], a[1], b[1]);
306 } 310 }
OLDNEW
« no previous file with comments | « src/pathops/SkDCubicLineIntersection.cpp ('k') | src/pathops/SkDQuadIntersection.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698