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 #include "SkPathOpsQuad.h" | 9 #include "SkPathOpsQuad.h" |
10 | 10 |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 B = 2*(-(a - b ) + g'*(d - e ) ) | 85 B = 2*(-(a - b ) + g'*(d - e ) ) |
86 C = ( (a ) - g'*(d ) - h' ) | 86 C = ( (a ) - g'*(d ) - h' ) |
87 */ | 87 */ |
88 | 88 |
89 | 89 |
90 class LineQuadraticIntersections { | 90 class LineQuadraticIntersections { |
91 public: | 91 public: |
92 LineQuadraticIntersections(const SkDQuad& q, const SkDLine& l, SkIntersectio
ns* i) | 92 LineQuadraticIntersections(const SkDQuad& q, const SkDLine& l, SkIntersectio
ns* i) |
93 : quad(q) | 93 : quad(q) |
94 , line(l) | 94 , line(l) |
95 , intersections(i) { | 95 , intersections(i) |
| 96 , fAllowNear(true) { |
| 97 } |
| 98 |
| 99 void allowNear(bool allow) { |
| 100 fAllowNear = allow; |
96 } | 101 } |
97 | 102 |
98 int intersectRay(double roots[2]) { | 103 int intersectRay(double roots[2]) { |
99 /* | 104 /* |
100 solve by rotating line+quad so line is horizontal, then finding the root
s | 105 solve by rotating line+quad so line is horizontal, then finding the root
s |
101 set up matrix to rotate quad to x-axis | 106 set up matrix to rotate quad to x-axis |
102 |cos(a) -sin(a)| | 107 |cos(a) -sin(a)| |
103 |sin(a) cos(a)| | 108 |sin(a) cos(a)| |
104 note that cos(a) = A(djacent) / Hypoteneuse | 109 note that cos(a) = A(djacent) / Hypoteneuse |
105 sin(a) = O(pposite) / Hypoteneuse | 110 sin(a) = O(pposite) / Hypoteneuse |
(...skipping 13 matching lines...) Expand all Loading... |
119 } | 124 } |
120 double A = r[2]; | 125 double A = r[2]; |
121 double B = r[1]; | 126 double B = r[1]; |
122 double C = r[0]; | 127 double C = r[0]; |
123 A += C - 2 * B; // A = a - 2*b + c | 128 A += C - 2 * B; // A = a - 2*b + c |
124 B -= C; // B = -(b - c) | 129 B -= C; // B = -(b - c) |
125 return SkDQuad::RootsValidT(A, 2 * B, C, roots); | 130 return SkDQuad::RootsValidT(A, 2 * B, C, roots); |
126 } | 131 } |
127 | 132 |
128 int intersect() { | 133 int intersect() { |
129 addEndPoints(); | 134 addExactEndPoints(); |
130 double rootVals[2]; | 135 double rootVals[2]; |
131 int roots = intersectRay(rootVals); | 136 int roots = intersectRay(rootVals); |
132 for (int index = 0; index < roots; ++index) { | 137 for (int index = 0; index < roots; ++index) { |
133 double quadT = rootVals[index]; | 138 double quadT = rootVals[index]; |
134 double lineT = findLineT(quadT); | 139 double lineT = findLineT(quadT); |
135 if (PinTs(&quadT, &lineT)) { | 140 if (PinTs(&quadT, &lineT)) { |
136 SkDPoint pt = line.xyAtT(lineT); | 141 SkDPoint pt = line.xyAtT(lineT); |
137 intersections->insert(quadT, lineT, pt); | 142 intersections->insert(quadT, lineT, pt); |
138 } | 143 } |
139 } | 144 } |
| 145 if (fAllowNear) { |
| 146 addNearEndPoints(); |
| 147 } |
140 return intersections->used(); | 148 return intersections->used(); |
141 } | 149 } |
142 | 150 |
143 int horizontalIntersect(double axisIntercept, double roots[2]) { | 151 int horizontalIntersect(double axisIntercept, double roots[2]) { |
144 double D = quad[2].fY; // f | 152 double D = quad[2].fY; // f |
145 double E = quad[1].fY; // e | 153 double E = quad[1].fY; // e |
146 double F = quad[0].fY; // d | 154 double F = quad[0].fY; // d |
147 D += F - 2 * E; // D = d - 2*e + f | 155 D += F - 2 * E; // D = d - 2*e + f |
148 E -= F; // E = -(d - e) | 156 E -= F; // E = -(d - e) |
149 F -= axisIntercept; | 157 F -= axisIntercept; |
150 return SkDQuad::RootsValidT(D, 2 * E, F, roots); | 158 return SkDQuad::RootsValidT(D, 2 * E, F, roots); |
151 } | 159 } |
152 | 160 |
153 int horizontalIntersect(double axisIntercept, double left, double right, boo
l flipped) { | 161 int horizontalIntersect(double axisIntercept, double left, double right, boo
l flipped) { |
154 addHorizontalEndPoints(left, right, axisIntercept); | 162 addExactHorizontalEndPoints(left, right, axisIntercept); |
155 double rootVals[2]; | 163 double rootVals[2]; |
156 int roots = horizontalIntersect(axisIntercept, rootVals); | 164 int roots = horizontalIntersect(axisIntercept, rootVals); |
157 for (int index = 0; index < roots; ++index) { | 165 for (int index = 0; index < roots; ++index) { |
158 double quadT = rootVals[index]; | 166 double quadT = rootVals[index]; |
159 SkDPoint pt = quad.xyAtT(quadT); | 167 SkDPoint pt = quad.xyAtT(quadT); |
160 double lineT = (pt.fX - left) / (right - left); | 168 double lineT = (pt.fX - left) / (right - left); |
161 if (PinTs(&quadT, &lineT)) { | 169 if (PinTs(&quadT, &lineT)) { |
162 intersections->insert(quadT, lineT, pt); | 170 intersections->insert(quadT, lineT, pt); |
163 } | 171 } |
164 } | 172 } |
| 173 if (fAllowNear) { |
| 174 addNearHorizontalEndPoints(left, right, axisIntercept); |
| 175 } |
165 if (flipped) { | 176 if (flipped) { |
166 intersections->flip(); | 177 intersections->flip(); |
167 } | 178 } |
168 return intersections->used(); | 179 return intersections->used(); |
169 } | 180 } |
170 | 181 |
171 int verticalIntersect(double axisIntercept, double roots[2]) { | 182 int verticalIntersect(double axisIntercept, double roots[2]) { |
172 double D = quad[2].fX; // f | 183 double D = quad[2].fX; // f |
173 double E = quad[1].fX; // e | 184 double E = quad[1].fX; // e |
174 double F = quad[0].fX; // d | 185 double F = quad[0].fX; // d |
175 D += F - 2 * E; // D = d - 2*e + f | 186 D += F - 2 * E; // D = d - 2*e + f |
176 E -= F; // E = -(d - e) | 187 E -= F; // E = -(d - e) |
177 F -= axisIntercept; | 188 F -= axisIntercept; |
178 return SkDQuad::RootsValidT(D, 2 * E, F, roots); | 189 return SkDQuad::RootsValidT(D, 2 * E, F, roots); |
179 } | 190 } |
180 | 191 |
181 int verticalIntersect(double axisIntercept, double top, double bottom, bool
flipped) { | 192 int verticalIntersect(double axisIntercept, double top, double bottom, bool
flipped) { |
182 addVerticalEndPoints(top, bottom, axisIntercept); | 193 addExactVerticalEndPoints(top, bottom, axisIntercept); |
183 double rootVals[2]; | 194 double rootVals[2]; |
184 int roots = verticalIntersect(axisIntercept, rootVals); | 195 int roots = verticalIntersect(axisIntercept, rootVals); |
185 for (int index = 0; index < roots; ++index) { | 196 for (int index = 0; index < roots; ++index) { |
186 double quadT = rootVals[index]; | 197 double quadT = rootVals[index]; |
187 SkDPoint pt = quad.xyAtT(quadT); | 198 SkDPoint pt = quad.xyAtT(quadT); |
188 double lineT = (pt.fY - top) / (bottom - top); | 199 double lineT = (pt.fY - top) / (bottom - top); |
189 if (PinTs(&quadT, &lineT)) { | 200 if (PinTs(&quadT, &lineT)) { |
190 intersections->insert(quadT, lineT, pt); | 201 intersections->insert(quadT, lineT, pt); |
191 } | 202 } |
192 } | 203 } |
| 204 if (fAllowNear) { |
| 205 addNearVerticalEndPoints(top, bottom, axisIntercept); |
| 206 } |
193 if (flipped) { | 207 if (flipped) { |
194 intersections->flip(); | 208 intersections->flip(); |
195 } | 209 } |
196 return intersections->used(); | 210 return intersections->used(); |
197 } | 211 } |
198 | 212 |
199 protected: | 213 protected: |
200 // add endpoints first to get zero and one t values exactly | 214 // add endpoints first to get zero and one t values exactly |
201 void addEndPoints() { | 215 void addExactEndPoints() { |
202 for (int qIndex = 0; qIndex < 3; qIndex += 2) { | 216 for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
203 bool foundEnd = false; | 217 double lineT = line.exactPoint(quad[qIndex]); |
204 for (int lIndex = 0; lIndex < 2; lIndex++) { | 218 if (lineT < 0) { |
205 if (quad[qIndex] == line[lIndex]) { | |
206 intersections->insert(qIndex >> 1, lIndex, line[lIndex]); | |
207 foundEnd = true; | |
208 } | |
209 } | |
210 if (foundEnd) { | |
211 continue; | 219 continue; |
212 } | 220 } |
213 // See if the quad end touches the line. | 221 double quadT = (double) (qIndex >> 1); |
214 double dist = line.isLeft(quad[qIndex]); // this distance isn't cart
esian | 222 intersections->insert(quadT, lineT, quad[qIndex]); |
215 SkDVector lineLen = line[1] - line[0]; // the x/y magnitudes of the
line | |
216 // compute the ULPS of the larger of the x/y deltas | |
217 double larger = SkTMax(SkTAbs(lineLen.fX), SkTAbs(lineLen.fY)); | |
218 if (!RoughlyEqualUlps(larger, larger + dist)) { // is the dist withi
n ULPS tolerance? | |
219 continue; | |
220 } | |
221 double lineT = findLineT(qIndex >> 1); | |
222 if (!between(0, lineT, 1)) { | |
223 continue; | |
224 } | |
225 SkDPoint linePt = line.xyAtT(lineT); | |
226 if (linePt.approximatelyEqual(quad[qIndex])) { | |
227 intersections->insert(qIndex >> 1, lineT, quad[qIndex]); | |
228 } | |
229 } | 223 } |
230 } | 224 } |
231 | 225 |
232 void addHorizontalEndPoints(double left, double right, double y) { | 226 void addNearEndPoints() { |
233 for (int qIndex = 0; qIndex < 3; qIndex += 2) { | 227 for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
234 if (!AlmostEqualUlps(quad[qIndex].fY, y)) { | 228 double quadT = (double) (qIndex >> 1); |
| 229 if (intersections->hasT(quadT)) { |
235 continue; | 230 continue; |
236 } | 231 } |
237 double x = quad[qIndex].fX; | 232 double lineT = line.nearPoint(quad[qIndex]); |
238 if (between(left, x, right)) { | 233 if (lineT < 0) { |
239 double t = (x - left) / (right - left); | 234 continue; |
240 intersections->insert(qIndex >> 1, t, quad[qIndex]); | |
241 } | 235 } |
| 236 intersections->insert(quadT, lineT, quad[qIndex]); |
| 237 } |
| 238 // FIXME: see if line end is nearly on quad |
| 239 } |
| 240 |
| 241 void addExactHorizontalEndPoints(double left, double right, double y) { |
| 242 for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
| 243 double lineT = SkDLine::ExactPointH(quad[qIndex], left, right, y); |
| 244 if (lineT < 0) { |
| 245 continue; |
| 246 } |
| 247 double quadT = (double) (qIndex >> 1); |
| 248 intersections->insert(quadT, lineT, quad[qIndex]); |
242 } | 249 } |
243 } | 250 } |
244 | 251 |
245 void addVerticalEndPoints(double top, double bottom, double x) { | 252 void addNearHorizontalEndPoints(double left, double right, double y) { |
246 for (int qIndex = 0; qIndex < 3; qIndex += 2) { | 253 for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
247 if (!AlmostEqualUlps(quad[qIndex].fX, x)) { | 254 double quadT = (double) (qIndex >> 1); |
| 255 if (intersections->hasT(quadT)) { |
248 continue; | 256 continue; |
249 } | 257 } |
250 double y = quad[qIndex].fY; | 258 double lineT = SkDLine::NearPointH(quad[qIndex], left, right, y); |
251 if (between(top, y, bottom)) { | 259 if (lineT < 0) { |
252 double t = (y - top) / (bottom - top); | 260 continue; |
253 intersections->insert(qIndex >> 1, t, quad[qIndex]); | |
254 } | 261 } |
| 262 intersections->insert(quadT, lineT, quad[qIndex]); |
255 } | 263 } |
| 264 // FIXME: see if line end is nearly on quad |
| 265 } |
| 266 |
| 267 void addExactVerticalEndPoints(double top, double bottom, double x) { |
| 268 for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
| 269 double lineT = SkDLine::ExactPointV(quad[qIndex], top, bottom, x); |
| 270 if (lineT < 0) { |
| 271 continue; |
| 272 } |
| 273 double quadT = (double) (qIndex >> 1); |
| 274 intersections->insert(quadT, lineT, quad[qIndex]); |
| 275 } |
| 276 } |
| 277 |
| 278 void addNearVerticalEndPoints(double top, double bottom, double x) { |
| 279 for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
| 280 double quadT = (double) (qIndex >> 1); |
| 281 if (intersections->hasT(quadT)) { |
| 282 continue; |
| 283 } |
| 284 double lineT = SkDLine::NearPointV(quad[qIndex], top, bottom, x); |
| 285 if (lineT < 0) { |
| 286 continue; |
| 287 } |
| 288 intersections->insert(quadT, lineT, quad[qIndex]); |
| 289 } |
| 290 // FIXME: see if line end is nearly on quad |
256 } | 291 } |
257 | 292 |
258 double findLineT(double t) { | 293 double findLineT(double t) { |
259 SkDPoint xy = quad.xyAtT(t); | 294 SkDPoint xy = quad.xyAtT(t); |
260 double dx = line[1].fX - line[0].fX; | 295 double dx = line[1].fX - line[0].fX; |
261 double dy = line[1].fY - line[0].fY; | 296 double dy = line[1].fY - line[0].fY; |
262 #if 0 | |
263 if (fabs(dx) > fabs(dy)) { | |
264 return (xy.fX - line[0].fX) / dx; | |
265 } | |
266 return (xy.fY - line[0].fY) / dy; | |
267 #else | |
268 double dxT = (xy.fX - line[0].fX) / dx; | 297 double dxT = (xy.fX - line[0].fX) / dx; |
269 double dyT = (xy.fY - line[0].fY) / dy; | 298 double dyT = (xy.fY - line[0].fY) / dy; |
270 if (!between(FLT_EPSILON, dxT, 1 - FLT_EPSILON) && between(0, dyT, 1)) { | 299 if (!between(FLT_EPSILON, dxT, 1 - FLT_EPSILON) && between(0, dyT, 1)) { |
271 return dyT; | 300 return dyT; |
272 } | 301 } |
273 if (!between(FLT_EPSILON, dyT, 1 - FLT_EPSILON) && between(0, dxT, 1)) { | 302 if (!between(FLT_EPSILON, dyT, 1 - FLT_EPSILON) && between(0, dxT, 1)) { |
274 return dxT; | 303 return dxT; |
275 } | 304 } |
276 return fabs(dx) > fabs(dy) ? dxT : dyT; | 305 return fabs(dx) > fabs(dy) ? dxT : dyT; |
277 #endif | |
278 } | 306 } |
279 | 307 |
280 static bool PinTs(double* quadT, double* lineT) { | 308 static bool PinTs(double* quadT, double* lineT) { |
281 if (!approximately_one_or_less(*lineT)) { | 309 if (!approximately_one_or_less(*lineT)) { |
282 return false; | 310 return false; |
283 } | 311 } |
284 if (!approximately_zero_or_more(*lineT)) { | 312 if (!approximately_zero_or_more(*lineT)) { |
285 return false; | 313 return false; |
286 } | 314 } |
287 if (precisely_less_than_zero(*quadT)) { | 315 *quadT = SkPinT(*quadT); |
288 *quadT = 0; | 316 *lineT = SkPinT(*lineT); |
289 } else if (precisely_greater_than_one(*quadT)) { | |
290 *quadT = 1; | |
291 } | |
292 if (precisely_less_than_zero(*lineT)) { | |
293 *lineT = 0; | |
294 } else if (precisely_greater_than_one(*lineT)) { | |
295 *lineT = 1; | |
296 } | |
297 return true; | 317 return true; |
298 } | 318 } |
299 | 319 |
300 private: | 320 private: |
301 const SkDQuad& quad; | 321 const SkDQuad& quad; |
302 const SkDLine& line; | 322 const SkDLine& line; |
303 SkIntersections* intersections; | 323 SkIntersections* intersections; |
| 324 bool fAllowNear; |
304 }; | 325 }; |
305 | 326 |
306 // utility for pairs of coincident quads | 327 // utility for pairs of coincident quads |
307 static double horizontalIntersect(const SkDQuad& quad, const SkDPoint& pt) { | 328 static double horizontalIntersect(const SkDQuad& quad, const SkDPoint& pt) { |
308 LineQuadraticIntersections q(quad, *(static_cast<SkDLine*>(0)), | 329 LineQuadraticIntersections q(quad, *(static_cast<SkDLine*>(0)), |
309 static_cast<SkIntersections*>(0)); | 330 static_cast<SkIntersections*>(0)); |
310 double rootVals[2]; | 331 double rootVals[2]; |
311 int roots = q.horizontalIntersect(pt.fY, rootVals); | 332 int roots = q.horizontalIntersect(pt.fY, rootVals); |
312 for (int index = 0; index < roots; ++index) { | 333 for (int index = 0; index < roots; ++index) { |
313 double t = rootVals[index]; | 334 double t = rootVals[index]; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
348 } | 369 } |
349 | 370 |
350 int SkIntersections::vertical(const SkDQuad& quad, double top, double bottom, do
uble x, | 371 int SkIntersections::vertical(const SkDQuad& quad, double top, double bottom, do
uble x, |
351 bool flipped) { | 372 bool flipped) { |
352 LineQuadraticIntersections q(quad, *(static_cast<SkDLine*>(0)), this); | 373 LineQuadraticIntersections q(quad, *(static_cast<SkDLine*>(0)), this); |
353 return q.verticalIntersect(x, top, bottom, flipped); | 374 return q.verticalIntersect(x, top, bottom, flipped); |
354 } | 375 } |
355 | 376 |
356 int SkIntersections::intersect(const SkDQuad& quad, const SkDLine& line) { | 377 int SkIntersections::intersect(const SkDQuad& quad, const SkDLine& line) { |
357 LineQuadraticIntersections q(quad, line, this); | 378 LineQuadraticIntersections q(quad, line, this); |
| 379 q.allowNear(fAllowNear); |
358 return q.intersect(); | 380 return q.intersect(); |
359 } | 381 } |
360 | 382 |
361 int SkIntersections::intersectRay(const SkDQuad& quad, const SkDLine& line) { | 383 int SkIntersections::intersectRay(const SkDQuad& quad, const SkDLine& line) { |
362 LineQuadraticIntersections q(quad, line, this); | 384 LineQuadraticIntersections q(quad, line, this); |
363 fUsed = q.intersectRay(fT[0]); | 385 fUsed = q.intersectRay(fT[0]); |
364 for (int index = 0; index < fUsed; ++index) { | 386 for (int index = 0; index < fUsed; ++index) { |
365 fPt[index] = quad.xyAtT(fT[0][index]); | 387 fPt[index] = quad.xyAtT(fT[0][index]); |
366 } | 388 } |
367 return fUsed; | 389 return fUsed; |
368 } | 390 } |
OLD | NEW |