blob: 52e751bd08d0129825b3cf0c097c3343d942a521 [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 "SkAddIntersections.h"
8#include "SkPathOpsBounds.h"
9
10#if DEBUG_ADD_INTERSECTING_TS
11
12static void debugShowLineIntersection(int pts, const SkIntersectionHelper& wt,
13 const SkIntersectionHelper& wn, const SkIntersections& i) {
14 SkASSERT(i.used() == pts);
15 if (!pts) {
16 SkDebugf("%s no intersect " LINE_DEBUG_STR " " LINE_DEBUG_STR "\n",
17 __FUNCTION__, LINE_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
18 return;
19 }
20 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " LINE_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
21 i[0][0], LINE_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
22 if (pts == 2) {
23 SkDebugf(" " T_DEBUG_STR(wtTs, 1) " " PT_DEBUG_STR, i[0][1], PT_DEBUG_DATA(i, 1));
24 }
25 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i[1][0], LINE_DEBUG_DATA(wn.pts()));
26 if (pts == 2) {
27 SkDebugf(" " T_DEBUG_STR(wnTs, 1), i[1][1]);
28 }
29 SkDebugf("\n");
30}
31
32static void debugShowQuadLineIntersection(int pts, const SkIntersectionHelper& wt,
33 const SkIntersectionHelper& wn,
34 const SkIntersections& i) {
35 SkASSERT(i.used() == pts);
36 if (!pts) {
37 SkDebugf("%s no intersect " QUAD_DEBUG_STR " " LINE_DEBUG_STR "\n",
38 __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
39 return;
40 }
41 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
42 i[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
43 for (int n = 1; n < pts; ++n) {
44 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n));
45 }
46 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i[1][0], LINE_DEBUG_DATA(wn.pts()));
47 for (int n = 1; n < pts; ++n) {
48 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]);
49 }
50 SkDebugf("\n");
51}
52
53static void debugShowQuadIntersection(int pts, const SkIntersectionHelper& wt,
54 const SkIntersectionHelper& wn, const SkIntersections& i) {
55 SkASSERT(i.used() == pts);
56 if (!pts) {
57 SkDebugf("%s no intersect " QUAD_DEBUG_STR " " QUAD_DEBUG_STR "\n",
58 __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts()));
59 return;
60 }
61 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
62 i[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
63 for (int n = 1; n < pts; ++n) {
64 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n));
65 }
66 SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i[1][0], QUAD_DEBUG_DATA(wn.pts()));
67 for (int n = 1; n < pts; ++n) {
68 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]);
69 }
70 SkDebugf("\n");
71}
72
73static void debugShowCubicLineIntersection(int pts, const SkIntersectionHelper& wt,
74 const SkIntersectionHelper& wn, const SkIntersections& i) {
75 SkASSERT(i.used() == pts);
76 if (!pts) {
77 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " LINE_DEBUG_STR "\n",
78 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
79 return;
80 }
81 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
82 i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
83 for (int n = 1; n < pts; ++n) {
84 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n));
85 }
86 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i[1][0], LINE_DEBUG_DATA(wn.pts()));
87 for (int n = 1; n < pts; ++n) {
88 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]);
89 }
90 SkDebugf("\n");
91}
92
93static void debugShowCubicQuadIntersection(int pts, const SkIntersectionHelper& wt,
94 const SkIntersectionHelper& wn, const SkIntersections& i) {
95 SkASSERT(i.used() == pts);
96 if (!pts) {
97 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " QUAD_DEBUG_STR "\n",
98 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts()));
99 return;
100 }
101 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
102 i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
103 for (int n = 1; n < pts; ++n) {
104 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n));
105 }
106 SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i[1][0], QUAD_DEBUG_DATA(wn.pts()));
107 for (int n = 1; n < pts; ++n) {
108 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]);
109 }
110 SkDebugf("\n");
111}
112
113static void debugShowCubicIntersection(int pts, const SkIntersectionHelper& wt,
114 const SkIntersectionHelper& wn, const SkIntersections& i) {
115 SkASSERT(i.used() == pts);
116 if (!pts) {
117 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " CUBIC_DEBUG_STR "\n",
118 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), CUBIC_DEBUG_DATA(wn.pts()));
119 return;
120 }
121 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
122 i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
123 for (int n = 1; n < pts; ++n) {
124 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n));
125 }
126 SkDebugf(" wnTs[0]=%g " CUBIC_DEBUG_STR, i[1][0], CUBIC_DEBUG_DATA(wn.pts()));
127 for (int n = 1; n < pts; ++n) {
128 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]);
129 }
130 SkDebugf("\n");
131}
132
133static void debugShowCubicIntersection(int pts, const SkIntersectionHelper& wt,
134 const SkIntersections& i) {
135 SkASSERT(i.used() == pts);
136 if (!pts) {
137 SkDebugf("%s no self intersect " CUBIC_DEBUG_STR "\n", __FUNCTION__,
138 CUBIC_DEBUG_DATA(wt.pts()));
139 return;
140 }
141 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
142 i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
143 SkDebugf(" " T_DEBUG_STR(wtTs, 1), i[1][0]);
144 SkDebugf("\n");
145}
146
147#else
148static void debugShowLineIntersection(int , const SkIntersectionHelper& ,
149 const SkIntersectionHelper& , const SkIntersections& ) {
150}
151
152static void debugShowQuadLineIntersection(int , const SkIntersectionHelper& ,
153 const SkIntersectionHelper& , const SkIntersections& ) {
154}
155
156static void debugShowQuadIntersection(int , const SkIntersectionHelper& ,
157 const SkIntersectionHelper& , const SkIntersections& ) {
158}
159
160static void debugShowCubicLineIntersection(int , const SkIntersectionHelper& ,
161 const SkIntersectionHelper& , const SkIntersections& ) {
162}
163
164static void debugShowCubicQuadIntersection(int , const SkIntersectionHelper& ,
165 const SkIntersectionHelper& , const SkIntersections& ) {
166}
167
168static void debugShowCubicIntersection(int , const SkIntersectionHelper& ,
169 const SkIntersectionHelper& , const SkIntersections& ) {
170}
171
172static void debugShowCubicIntersection(int , const SkIntersectionHelper& ,
173 const SkIntersections& ) {
174}
175#endif
176
177bool AddIntersectTs(SkOpContour* test, SkOpContour* next) {
178 if (test != next) {
caryclark@google.com570863f2013-09-16 15:55:01 +0000179 if (AlmostLessUlps(test->bounds().fBottom, next->bounds().fTop)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000180 return false;
181 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000182 // OPTIMIZATION: outset contour bounds a smidgen instead?
caryclark@google.com07393ca2013-04-08 11:47:37 +0000183 if (!SkPathOpsBounds::Intersects(test->bounds(), next->bounds())) {
184 return true;
185 }
186 }
187 SkIntersectionHelper wt;
188 wt.init(test);
189 bool foundCommonContour = test == next;
190 do {
191 SkIntersectionHelper wn;
192 wn.init(next);
193 if (test == next && !wn.startAfter(wt)) {
194 continue;
195 }
196 do {
197 if (!SkPathOpsBounds::Intersects(wt.bounds(), wn.bounds())) {
198 continue;
199 }
200 int pts = 0;
201 SkIntersections ts;
202 bool swap = false;
203 switch (wt.segmentType()) {
204 case SkIntersectionHelper::kHorizontalLine_Segment:
205 swap = true;
206 switch (wn.segmentType()) {
207 case SkIntersectionHelper::kHorizontalLine_Segment:
208 case SkIntersectionHelper::kVerticalLine_Segment:
209 case SkIntersectionHelper::kLine_Segment: {
210 pts = ts.lineHorizontal(wn.pts(), wt.left(),
211 wt.right(), wt.y(), wt.xFlipped());
caryclark@google.coma5e55922013-05-07 18:51:31 +0000212 debugShowLineIntersection(pts, wn, wt, ts);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000213 break;
214 }
215 case SkIntersectionHelper::kQuad_Segment: {
216 pts = ts.quadHorizontal(wn.pts(), wt.left(),
217 wt.right(), wt.y(), wt.xFlipped());
218 debugShowQuadLineIntersection(pts, wn, wt, ts);
219 break;
220 }
221 case SkIntersectionHelper::kCubic_Segment: {
222 pts = ts.cubicHorizontal(wn.pts(), wt.left(),
223 wt.right(), wt.y(), wt.xFlipped());
224 debugShowCubicLineIntersection(pts, wn, wt, ts);
225 break;
226 }
227 default:
228 SkASSERT(0);
229 }
230 break;
231 case SkIntersectionHelper::kVerticalLine_Segment:
232 swap = true;
233 switch (wn.segmentType()) {
234 case SkIntersectionHelper::kHorizontalLine_Segment:
235 case SkIntersectionHelper::kVerticalLine_Segment:
236 case SkIntersectionHelper::kLine_Segment: {
237 pts = ts.lineVertical(wn.pts(), wt.top(),
238 wt.bottom(), wt.x(), wt.yFlipped());
caryclark@google.coma5e55922013-05-07 18:51:31 +0000239 debugShowLineIntersection(pts, wn, wt, ts);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000240 break;
241 }
242 case SkIntersectionHelper::kQuad_Segment: {
243 pts = ts.quadVertical(wn.pts(), wt.top(),
244 wt.bottom(), wt.x(), wt.yFlipped());
245 debugShowQuadLineIntersection(pts, wn, wt, ts);
246 break;
247 }
248 case SkIntersectionHelper::kCubic_Segment: {
249 pts = ts.cubicVertical(wn.pts(), wt.top(),
250 wt.bottom(), wt.x(), wt.yFlipped());
251 debugShowCubicLineIntersection(pts, wn, wt, ts);
252 break;
253 }
254 default:
255 SkASSERT(0);
256 }
257 break;
258 case SkIntersectionHelper::kLine_Segment:
259 switch (wn.segmentType()) {
260 case SkIntersectionHelper::kHorizontalLine_Segment:
261 pts = ts.lineHorizontal(wt.pts(), wn.left(),
262 wn.right(), wn.y(), wn.xFlipped());
263 debugShowLineIntersection(pts, wt, wn, ts);
264 break;
265 case SkIntersectionHelper::kVerticalLine_Segment:
266 pts = ts.lineVertical(wt.pts(), wn.top(),
267 wn.bottom(), wn.x(), wn.yFlipped());
268 debugShowLineIntersection(pts, wt, wn, ts);
269 break;
270 case SkIntersectionHelper::kLine_Segment: {
271 pts = ts.lineLine(wt.pts(), wn.pts());
272 debugShowLineIntersection(pts, wt, wn, ts);
273 break;
274 }
275 case SkIntersectionHelper::kQuad_Segment: {
276 swap = true;
277 pts = ts.quadLine(wn.pts(), wt.pts());
278 debugShowQuadLineIntersection(pts, wn, wt, ts);
279 break;
280 }
281 case SkIntersectionHelper::kCubic_Segment: {
282 swap = true;
283 pts = ts.cubicLine(wn.pts(), wt.pts());
284 debugShowCubicLineIntersection(pts, wn, wt, ts);
285 break;
286 }
287 default:
288 SkASSERT(0);
289 }
290 break;
291 case SkIntersectionHelper::kQuad_Segment:
292 switch (wn.segmentType()) {
293 case SkIntersectionHelper::kHorizontalLine_Segment:
294 pts = ts.quadHorizontal(wt.pts(), wn.left(),
295 wn.right(), wn.y(), wn.xFlipped());
296 debugShowQuadLineIntersection(pts, wt, wn, ts);
297 break;
298 case SkIntersectionHelper::kVerticalLine_Segment:
299 pts = ts.quadVertical(wt.pts(), wn.top(),
300 wn.bottom(), wn.x(), wn.yFlipped());
301 debugShowQuadLineIntersection(pts, wt, wn, ts);
302 break;
303 case SkIntersectionHelper::kLine_Segment: {
304 pts = ts.quadLine(wt.pts(), wn.pts());
305 debugShowQuadLineIntersection(pts, wt, wn, ts);
306 break;
307 }
308 case SkIntersectionHelper::kQuad_Segment: {
309 pts = ts.quadQuad(wt.pts(), wn.pts());
310 debugShowQuadIntersection(pts, wt, wn, ts);
311 break;
312 }
313 case SkIntersectionHelper::kCubic_Segment: {
314 swap = true;
315 pts = ts.cubicQuad(wn.pts(), wt.pts());
316 debugShowCubicQuadIntersection(pts, wn, wt, ts);
317 break;
318 }
319 default:
320 SkASSERT(0);
321 }
322 break;
323 case SkIntersectionHelper::kCubic_Segment:
324 switch (wn.segmentType()) {
325 case SkIntersectionHelper::kHorizontalLine_Segment:
326 pts = ts.cubicHorizontal(wt.pts(), wn.left(),
327 wn.right(), wn.y(), wn.xFlipped());
328 debugShowCubicLineIntersection(pts, wt, wn, ts);
329 break;
330 case SkIntersectionHelper::kVerticalLine_Segment:
331 pts = ts.cubicVertical(wt.pts(), wn.top(),
332 wn.bottom(), wn.x(), wn.yFlipped());
333 debugShowCubicLineIntersection(pts, wt, wn, ts);
334 break;
335 case SkIntersectionHelper::kLine_Segment: {
336 pts = ts.cubicLine(wt.pts(), wn.pts());
337 debugShowCubicLineIntersection(pts, wt, wn, ts);
338 break;
339 }
340 case SkIntersectionHelper::kQuad_Segment: {
341 pts = ts.cubicQuad(wt.pts(), wn.pts());
342 debugShowCubicQuadIntersection(pts, wt, wn, ts);
343 break;
344 }
345 case SkIntersectionHelper::kCubic_Segment: {
346 pts = ts.cubicCubic(wt.pts(), wn.pts());
347 debugShowCubicIntersection(pts, wt, wn, ts);
348 break;
349 }
350 default:
351 SkASSERT(0);
352 }
353 break;
354 default:
355 SkASSERT(0);
356 }
357 if (!foundCommonContour && pts > 0) {
358 test->addCross(next);
359 next->addCross(test);
360 foundCommonContour = true;
361 }
362 // in addition to recording T values, record matching segment
363 if (pts == 2) {
364 if (wn.segmentType() <= SkIntersectionHelper::kLine_Segment
365 && wt.segmentType() <= SkIntersectionHelper::kLine_Segment) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000366 if (wt.addCoincident(wn, ts, swap)) {
367 continue;
368 }
369 ts.cleanUpCoincidence(); // prefer (t == 0 or t == 1)
370 pts = 1;
371 } else if (wn.segmentType() >= SkIntersectionHelper::kQuad_Segment
caryclark@google.com07393ca2013-04-08 11:47:37 +0000372 && wt.segmentType() >= SkIntersectionHelper::kQuad_Segment
373 && ts.isCoincident(0)) {
374 SkASSERT(ts.coincidentUsed() == 2);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000375 if (wt.addCoincident(wn, ts, swap)) {
376 continue;
377 }
378 ts.cleanUpCoincidence(); // prefer (t == 0 or t == 1)
379 pts = 1;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000380 }
381 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000382 if (pts >= 2) {
383 for (int pt = 0; pt < pts - 1; ++pt) {
384 const SkDPoint& point = ts.pt(pt);
385 const SkDPoint& next = ts.pt(pt + 1);
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000386 if (wt.isPartial(ts[swap][pt], ts[swap][pt + 1], point, next)
387 && wn.isPartial(ts[!swap][pt], ts[!swap][pt + 1], point, next)) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000388 if (!wt.addPartialCoincident(wn, ts, pt, swap)) {
389 // remove extra point if two map to same float values
390 ts.cleanUpCoincidence(); // prefer (t == 0 or t == 1)
391 pts = 1;
392 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000393 }
394 }
395 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000396 for (int pt = 0; pt < pts; ++pt) {
397 SkASSERT(ts[0][pt] >= 0 && ts[0][pt] <= 1);
398 SkASSERT(ts[1][pt] >= 0 && ts[1][pt] <= 1);
399 SkPoint point = ts.pt(pt).asSkPoint();
caryclarkdac1d172014-06-17 05:15:38 -0700400 wt.alignTPt(wn, swap, pt, &ts, &point);
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +0000401 int testTAt = wt.addT(wn, point, ts[swap][pt]);
402 int nextTAt = wn.addT(wt, point, ts[!swap][pt]);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000403 wt.addOtherT(testTAt, ts[!swap][pt], nextTAt);
404 wn.addOtherT(nextTAt, ts[swap][pt], testTAt);
405 }
406 } while (wn.advance());
407 } while (wt.advance());
408 return true;
409}
410
411void AddSelfIntersectTs(SkOpContour* test) {
412 SkIntersectionHelper wt;
413 wt.init(test);
414 do {
415 if (wt.segmentType() != SkIntersectionHelper::kCubic_Segment) {
416 continue;
417 }
418 SkIntersections ts;
419 int pts = ts.cubic(wt.pts());
420 debugShowCubicIntersection(pts, wt, ts);
421 if (!pts) {
422 continue;
423 }
424 SkASSERT(pts == 1);
425 SkASSERT(ts[0][0] >= 0 && ts[0][0] <= 1);
426 SkASSERT(ts[1][0] >= 0 && ts[1][0] <= 1);
427 SkPoint point = ts.pt(0).asSkPoint();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000428 int testTAt = wt.addSelfT(point, ts[0][0]);
429 int nextTAt = wt.addSelfT(point, ts[1][0]);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000430 wt.addOtherT(testTAt, ts[1][0], nextTAt);
431 wt.addOtherT(nextTAt, ts[0][0], testTAt);
432 } while (wt.advance());
433}
434
435// resolve any coincident pairs found while intersecting, and
436// see if coincidence is formed by clipping non-concident segments
caryclark@google.comd892bd82013-06-17 14:10:36 +0000437void CoincidenceCheck(SkTArray<SkOpContour*, true>* contourList, int total) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000438 int contourCount = (*contourList).count();
439 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
440 SkOpContour* contour = (*contourList)[cIndex];
caryclarkdac1d172014-06-17 05:15:38 -0700441 contour->resolveNearCoincidence();
442 }
443 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
444 SkOpContour* contour = (*contourList)[cIndex];
caryclark@google.com07393ca2013-04-08 11:47:37 +0000445 contour->addCoincidentPoints();
446 }
447 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
448 SkOpContour* contour = (*contourList)[cIndex];
449 contour->calcCoincidentWinding();
450 }
451 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
452 SkOpContour* contour = (*contourList)[cIndex];
caryclark@google.com570863f2013-09-16 15:55:01 +0000453 contour->calcPartialCoincidentWinding();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000454 }
455}