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

Side by Side Diff: src/pathops/SkPathOpsTSect.h

Issue 853223002: new files for pathops geometric intersection (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: remove visualizer tool so cl contains only pure adds Created 5 years, 11 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
« no previous file with comments | « src/pathops/SkPathOpsTQuadSect.cpp ('k') | tests/PathOpsBuildUseTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2014 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
8 #include "SkChunkAlloc.h"
9 #include "SkPathOpsRect.h"
10 #include "SkPathOpsQuad.h"
11 #include "SkIntersections.h"
12 #include "SkTArray.h"
13
14 /* TCurve is either SkDQuadratic or SkDCubic */
15 template<typename TCurve>
16 class SkTCoincident {
17 public:
18 bool isCoincident() const {
19 return fCoincident;
20 }
21
22 void init() {
23 fCoincident = false;
24 SkDEBUGCODE(fPerpPt.fX = fPerpPt.fY = SK_ScalarNaN);
25 SkDEBUGCODE(fPerpT = SK_ScalarNaN);
26 }
27
28 void markCoincident() {
29 if (!fCoincident) {
30 fPerpT = -1;
31 }
32 fCoincident = true;
33 }
34
35 const SkDPoint& perpPt() const {
36 return fPerpPt;
37 }
38
39 double perpT() const {
40 return fPerpT;
41 }
42
43 void setPerp(const TCurve& c1, double t, const SkDPoint& cPt, const TCurve& );
44
45 private:
46 SkDPoint fPerpPt;
47 double fPerpT; // perpendicular intersection on opposite curve
48 bool fCoincident;
49 };
50
51 template<typename TCurve> class SkTSect;
52
53 /* Curve is either TCurve or SkDCubic */
54 template<typename TCurve>
55 class SkTSpan {
56 public:
57 void init(const TCurve& );
58 void initBounds(const TCurve& );
59
60 double closestBoundedT(const SkDPoint& pt) const;
61
62 bool contains(double t) const {
63 return !! const_cast<SkTSpan*>(this)->innerFind(t);
64 }
65
66 bool contains(const SkTSpan* span) const;
67
68 double endT() const {
69 return fEndT;
70 }
71
72 SkTSpan* find(double t) {
73 SkTSpan* result = innerFind(t);
74 SkASSERT(result);
75 return result;
76 }
77
78 bool intersects(const SkTSpan* span, bool* check);
79
80 const SkTSpan* next() const {
81 return fNext;
82 }
83
84 const TCurve& part() const {
85 return fPart;
86 }
87
88 void reset() {
89 fBounded.reset();
90 }
91
92 bool split(SkTSpan* work) {
93 return splitAt(work, (work->fStartT + work->fEndT) * 0.5);
94 }
95
96 bool splitAt(SkTSpan* work, double t);
97
98 double startT() const {
99 return fStartT;
100 }
101
102 bool tightBoundsIntersects(const SkTSpan* span) const;
103
104 // implementation is for testing only
105 void dump() const {
106 dump(NULL);
107 }
108
109 private:
110 SkTSpan* innerFind(double t);
111 bool linearIntersects(const TCurve& ) const;
112
113 // implementation is for testing only
114 #if DEBUG_T_SECT
115 int debugID(const SkTSect<TCurve>* ) const { return fDebugID; }
116 #else
117 int debugID(const SkTSect<TCurve>* ) const;
118 #endif
119 void dump(const SkTSect<TCurve>* ) const;
120 void dumpID(const SkTSect<TCurve>* ) const;
121
122 #if DEBUG_T_SECT
123 void validate() const;
124 #endif
125
126 TCurve fPart;
127 SkTCoincident<TCurve> fCoinStart;
128 SkTCoincident<TCurve> fCoinEnd;
129 SkSTArray<4, SkTSpan*, true> fBounded;
130 SkTSpan* fPrev;
131 SkTSpan* fNext;
132 SkDRect fBounds;
133 double fStartT;
134 double fEndT;
135 double fBoundsMax;
136 bool fCollapsed;
137 bool fHasPerp;
138 bool fIsLinear;
139 #if DEBUG_T_SECT
140 int fDebugID;
141 bool fDebugDeleted;
142 #endif
143 friend class SkTSect<TCurve>;
144 };
145
146 template<typename TCurve>
147 class SkTSect {
148 public:
149 SkTSect(const TCurve& c PATH_OPS_DEBUG_PARAMS(int id));
150 static void BinarySearch(SkTSect* sect1, SkTSect* sect2, SkIntersections* in tersections);
151
152 // for testing only
153 void dump() const;
154 void dumpBoth(const SkTSect& opp) const;
155 void dumpBoth(const SkTSect* opp) const;
156 void dumpCurves() const;
157
158 private:
159 enum {
160 kZeroS1Set = 1,
161 kOneS1Set = 2,
162 kZeroS2Set = 4,
163 kOneS2Set = 8
164 };
165
166 SkTSpan<TCurve>* addOne();
167 bool binarySearchCoin(const SkTSect& , double tStart, double tStep, double* t, double* oppT);
168 SkTSpan<TCurve>* boundsMax() const;
169 void coincidentCheck(SkTSect* sect2);
170 static int EndsEqual(const SkTSect* sect1, const SkTSect* sect2, SkIntersect ions* );
171 bool intersects(SkTSpan<TCurve>* span, const SkTSect* opp,
172 const SkTSpan<TCurve>* oppSpan) const;
173 void onCurveCheck(SkTSect* sect2, SkTSpan<TCurve>* first, SkTSpan<TCurve>* l ast);
174 void recoverCollapsed();
175 void removeSpan(SkTSpan<TCurve>* span);
176 void removeOne(const SkTSpan<TCurve>* test, SkTSpan<TCurve>* span);
177 void removeSpans(SkTSpan<TCurve>* span, SkTSect* opp);
178 void setPerp(const TCurve& opp, SkTSpan<TCurve>* first, SkTSpan<TCurve>* las t);
179 const SkTSpan<TCurve>* tail() const;
180 void trim(SkTSpan<TCurve>* span, SkTSect* opp);
181
182 #if DEBUG_T_SECT
183 int debugID() const { return fDebugID; }
184 void validate() const;
185 #else
186 int debugID() const { return 0; }
187 #endif
188 const TCurve& fCurve;
189 SkChunkAlloc fHeap;
190 SkTSpan<TCurve>* fHead;
191 SkTSpan<TCurve>* fDeleted;
192 int fActiveCount;
193 #if DEBUG_T_SECT
194 int fDebugID;
195 int fDebugCount;
196 int fDebugAllocatedCount;
197 #endif
198 friend class SkTSpan<TCurve>; // only used by debug id
199 };
200
201 #define COINCIDENT_SPAN_COUNT 9
202
203 template<typename TCurve>
204 void SkTCoincident<TCurve>::setPerp(const TCurve& c1, double t,
205 const SkDPoint& cPt, const TCurve& c2) {
206 SkDVector dxdy = c1.dxdyAtT(t);
207 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
208 SkIntersections i;
209 int used = i.intersectRay(c2, perp);
210 // only keep closest
211 if (used == 0) {
212 fPerpT = -1;
213 return;
214 }
215 fPerpT = i[0][0];
216 fPerpPt = i.pt(0);
217 SkASSERT(used <= 2);
218 if (used == 2) {
219 double distSq = (fPerpPt - cPt).lengthSquared();
220 double dist2Sq = (i.pt(1) - cPt).lengthSquared();
221 if (dist2Sq < distSq) {
222 fPerpT = i[0][1];
223 fPerpPt = i.pt(1);
224 }
225 }
226 fCoincident = cPt.approximatelyEqual(fPerpPt);
227 #if DEBUG_T_SECT
228 if (fCoincident) {
229 SkDebugf(""); // allow setting breakpoint
230 }
231 #endif
232 }
233
234 template<typename TCurve>
235 void SkTSpan<TCurve>::init(const TCurve& c) {
236 fPrev = fNext = NULL;
237 fIsLinear = false;
238 fStartT = 0;
239 fEndT = 1;
240 initBounds(c);
241 }
242
243 template<typename TCurve>
244 void SkTSpan<TCurve>::initBounds(const TCurve& c) {
245 fPart = c.subDivide(fStartT, fEndT);
246 fBounds.setBounds(fPart);
247 fCoinStart.init();
248 fCoinEnd.init();
249 fBoundsMax = SkTMax(fBounds.width(), fBounds.height());
250 fCollapsed = fPart.collapsed();
251 fHasPerp = false;
252 #if DEBUG_T_SECT
253 fDebugDeleted = false;
254 if (fCollapsed) {
255 SkDebugf(""); // for convenient breakpoints
256 }
257 #endif
258 }
259
260 template<typename TCurve>
261 double SkTSpan<TCurve>::closestBoundedT(const SkDPoint& pt) const {
262 int count = fBounded.count();
263 double result = -1;
264 double closest = FLT_MAX;
265 for (int index = 0; index < count; ++index) {
266 const SkTSpan* test = fBounded[index];
267 double startDist = test->fPart[0].distanceSquared(pt);
268 if (closest > startDist) {
269 closest = startDist;
270 result = test->fStartT;
271 }
272 double endDist = test->fPart[TCurve::kPointLast].distanceSquared(pt);
273 if (closest > endDist) {
274 closest = endDist;
275 result = test->fEndT;
276 }
277 }
278 SkASSERT(between(0, result, 1));
279 return result;
280 }
281
282 template<typename TCurve>
283 bool SkTSpan<TCurve>::contains(const SkTSpan* span) const {
284 int count = fBounded.count();
285 for (int index = 0; index < count; ++index) {
286 const SkTSpan* test = fBounded[index];
287 if (span == test) {
288 return true;
289 }
290 }
291 return false;
292 }
293
294 template<typename TCurve>
295 SkTSpan<TCurve>* SkTSpan<TCurve>::innerFind(double t) {
296 SkTSpan* work = this;
297 do {
298 if (between(work->fStartT, t, work->fEndT)) {
299 return work;
300 }
301 } while ((work = work->fNext));
302 return NULL;
303 }
304
305 // OPTIMIZE ? If at_most_end_pts_in_common detects that one quad is near linear,
306 // use line intersection to guess a better split than 0.5
307 // OPTIMIZE Once at_most_end_pts_in_common detects linear, mark span so all futu re splits are linear
308 template<typename TCurve>
309 bool SkTSpan<TCurve>::intersects(const SkTSpan* span, bool* check) {
310 if (!fBounds.intersects(span->fBounds)) {
311 *check = false; // no need to check to see if the bounds have end point s in common
312 return false;
313 }
314 if (!fIsLinear && fPart.hullIntersects(span->fPart, check)) {
315 if (!*check) {
316 return true;
317 }
318 fIsLinear = true;
319 }
320 if (fIsLinear) {
321 *check = false;
322 return linearIntersects(span->fPart);
323 }
324 return *check;
325 }
326
327 template<typename TCurve>
328 bool SkTSpan<TCurve>::linearIntersects(const TCurve& q2) const {
329 // looks like q1 is near-linear
330 int start = 0, end = TCurve::kPointCount - 1; // the outside points are usu ally the extremes
331 if (!fPart.controlsInside()) {
332 double dist = 0; // if there's any question, compute distance to find b est outsiders
333 for (int outer = 0; outer < TCurve::kPointCount - 1; ++outer) {
334 for (int inner = outer + 1; inner < TCurve::kPointCount; ++inner) {
335 double test = (fPart[outer] - fPart[inner]).lengthSquared();
336 if (dist > test) {
337 continue;
338 }
339 dist = test;
340 start = outer;
341 end = inner;
342 }
343 }
344 }
345 // see if q2 is on one side of the line formed by the extreme points
346 double origX = fPart[start].fX;
347 double origY = fPart[start].fY;
348 double adj = fPart[end].fX - origX;
349 double opp = fPart[end].fY - origY;
350 double sign;
351 for (int n = 0; n < TCurve::kPointCount; ++n) {
352 double test = (q2[n].fY - origY) * adj - (q2[n].fX - origX) * opp;
353 if (precisely_zero(test)) {
354 return true;
355 }
356 if (n == 0) {
357 sign = test;
358 continue;
359 }
360 if (test * sign < 0) {
361 return true;
362 }
363 }
364 return false;
365 }
366
367 template<typename TCurve>
368 bool SkTSpan<TCurve>::splitAt(SkTSpan* work, double t) {
369 fStartT = t;
370 fEndT = work->fEndT;
371 if (fStartT == fEndT) {
372 fCollapsed = true;
373 return false;
374 }
375 work->fEndT = t;
376 if (work->fStartT == work->fEndT) {
377 work->fCollapsed = true;
378 return false;
379 }
380 fPrev = work;
381 fNext = work->fNext;
382 fIsLinear = work->fIsLinear;
383 work->fNext = this;
384 if (fNext) {
385 fNext->fPrev = this;
386 }
387 fBounded = work->fBounded;
388 int count = fBounded.count();
389 for (int index = 0; index < count; ++index) {
390 fBounded[index]->fBounded.push_back() = this;
391 }
392 return true;
393 }
394
395 template<typename TCurve>
396 bool SkTSpan<TCurve>::tightBoundsIntersects(const SkTSpan* span) const {
397 // skew all to an axis
398 SkDVector v2_0 = fPart[TCurve::kPointLast] - fPart[0];
399 bool skewToXAxis = fabs(v2_0.fX) > fabs(v2_0.fY);
400 double ratio = skewToXAxis ? v2_0.fY / v2_0.fX : v2_0.fX / v2_0.fY;
401 TCurve r1 = fPart;
402 if (skewToXAxis) {
403 r1[1].fY -= (fPart[1].fX - r1[0].fX) * ratio;
404 if (TCurve::IsCubic()) {
405 r1[2].fY -= (fPart[2].fX - r1[0].fX) * ratio;
406 r1[3].fY = r1[0].fY;
407 } else {
408 r1[2].fY = r1[0].fY;
409 }
410 } else {
411 r1[1].fX -= (fPart[1].fY - r1[0].fY) * ratio;
412 if (TCurve::IsCubic()) {
413 r1[2].fX -= (fPart[2].fY - r1[0].fY) * ratio;
414 r1[3].fX = r1[0].fX;
415 } else {
416 r1[2].fX = r1[0].fX;
417 }
418 }
419 // compute the tight skewed bounds
420 SkDRect bounds;
421 bounds.setBounds(r1);
422 // see if opposite ends are within range of tight skewed bounds
423 TCurve r2 = span->fPart;
424 for (int i = 0; i < TCurve::kPointCount; i += 2) {
425 if (skewToXAxis) {
426 r2[i].fY -= (r2[i].fX - r1[0].fX) * ratio;
427 if (between(bounds.fTop, r2[i].fY, bounds.fBottom)) {
428 return true;
429 }
430 } else {
431 r2[i].fX -= (r2[i].fY - r1[0].fY) * ratio;
432 if (between(bounds.fLeft, r2[i].fX, bounds.fRight)) {
433 return true;
434 }
435 }
436 }
437 // see if opposite ends are on either side of tight skewed bounds
438 if ((skewToXAxis ? (r2[0].fY - r1[0].fY) * (r2[TCurve::kPointLast].fY - r1[0 ].fY)
439 : (r2[0].fX - r1[0].fX) * (r2[TCurve::kPointLast].fX - r 1[0].fX)) < 0) {
440 return true;
441 }
442 // compute opposite tight skewed bounds
443 if (skewToXAxis) {
444 r2[1].fY -= (r2[1].fX - r1[0].fX) * ratio;
445 if (TCurve::IsCubic()) {
446 r2[2].fY -= (r2[2].fX - r1[0].fX) * ratio;
447 }
448 } else {
449 r2[1].fX -= (r2[1].fY - r1[0].fY) * ratio;
450 if (TCurve::IsCubic()) {
451 r2[2].fX -= (r2[2].fY - r1[0].fY) * ratio;
452 }
453 }
454 SkDRect sBounds;
455 sBounds.setBounds(r2);
456 // see if tight bounds overlap
457 if (skewToXAxis) {
458 return bounds.fTop <= sBounds.fBottom && sBounds.fTop <= bounds.fBottom;
459 } else {
460 return bounds.fLeft <= sBounds.fRight && sBounds.fLeft <= bounds.fRight;
461 }
462 }
463
464 #if DEBUG_T_SECT
465 template<typename TCurve>
466 void SkTSpan<TCurve>::validate() const {
467 SkASSERT(fNext == NULL || fNext != fPrev);
468 SkASSERT(fNext == NULL || this == fNext->fPrev);
469 SkASSERT(fBounds.width() || fBounds.height());
470 SkASSERT(fBoundsMax == SkTMax(fBounds.width(), fBounds.height()));
471 SkASSERT(0 <= fStartT);
472 SkASSERT(fEndT <= 1);
473 SkASSERT(fStartT < fEndT);
474 SkASSERT(fBounded.count() > 0);
475 for (int index = 0; index < fBounded.count(); ++index) {
476 const SkTSpan* overlap = fBounded[index];
477 SkASSERT(((fDebugID ^ overlap->fDebugID) & 1) == 1);
478 SkASSERT(overlap->contains(this));
479 }
480 }
481 #endif
482
483 template<typename TCurve>
484 SkTSect<TCurve>::SkTSect(const TCurve& c PATH_OPS_DEBUG_PARAMS(int id))
485 : fCurve(c)
486 , fHeap(sizeof(SkTSpan<TCurve>) * 4)
487 , fDeleted(NULL)
488 , fActiveCount(0)
489 PATH_OPS_DEBUG_PARAMS(fDebugID(id))
490 PATH_OPS_DEBUG_PARAMS(fDebugCount(0))
491 PATH_OPS_DEBUG_PARAMS(fDebugAllocatedCount(0))
492 {
493 fHead = addOne();
494 fHead->init(c);
495 }
496
497 template<typename TCurve>
498 SkTSpan<TCurve>* SkTSect<TCurve>::addOne() {
499 SkTSpan<TCurve>* result;
500 if (fDeleted) {
501 result = fDeleted;
502 result->reset();
503 fDeleted = result->fNext;
504 } else {
505 result = SkNEW_PLACEMENT(fHeap.allocThrow(sizeof(SkTSpan<TCurve>)), SkTS pan<TCurve>);
506 #if DEBUG_T_SECT
507 ++fDebugAllocatedCount;
508 #endif
509 }
510 ++fActiveCount;
511 #if DEBUG_T_SECT
512 result->fDebugID = fDebugCount++ * 2 + fDebugID;
513 #endif
514 return result;
515 }
516
517 template<typename TCurve>
518 bool SkTSect<TCurve>::binarySearchCoin(const SkTSect& sect2, double tStart, doub le tStep,
519 double* resultT, double* oppT) {
520 SkTSpan<TCurve> work;
521 double result = work.fStartT = work.fEndT = tStart;
522 SkDPoint last = fCurve.ptAtT(tStart);
523 SkDPoint oppPt;
524 bool flip = false;
525 SkDEBUGCODE(bool down = tStep < 0);
526 const TCurve& opp = sect2.fCurve;
527 do {
528 tStep *= 0.5;
529 work.fStartT += tStep;
530 if (flip) {
531 tStep = -tStep;
532 flip = false;
533 }
534 work.initBounds(fCurve);
535 if (work.fCollapsed) {
536 return false;
537 }
538 if (last.approximatelyEqual(work.fPart[0])) {
539 break;
540 }
541 last = work.fPart[0];
542 work.fCoinStart.setPerp(fCurve, work.fStartT, last, opp);
543 if (work.fCoinStart.isCoincident()) {
544 double oppTTest = work.fCoinStart.perpT();
545 if (sect2.fHead->contains(oppTTest)) {
546 *oppT = oppTTest;
547 oppPt = work.fCoinStart.perpPt();
548 SkASSERT(down ? result > work.fStartT : result < work.fStartT);
549 result = work.fStartT;
550 continue;
551 }
552 }
553 tStep = -tStep;
554 flip = true;
555 } while (true);
556 if (last.approximatelyEqual(fCurve[0])) {
557 result = 0;
558 } else if (last.approximatelyEqual(fCurve[TCurve::kPointLast])) {
559 result = 1;
560 }
561 if (oppPt.approximatelyEqual(opp[0])) {
562 *oppT = 0;
563 } else if (oppPt.approximatelyEqual(opp[TCurve::kPointLast])) {
564 *oppT = 1;
565 }
566 *resultT = result;
567 return true;
568 }
569
570 // OPTIMIZE ? keep a sorted list of sizes in the form of a doubly-linked list in quad span
571 // so that each quad sect has a pointer to the largest, and can updat e it as spans
572 // are split
573 template<typename TCurve>
574 SkTSpan<TCurve>* SkTSect<TCurve>::boundsMax() const {
575 SkTSpan<TCurve>* test = fHead;
576 SkTSpan<TCurve>* largest = fHead;
577 bool largestCoin = largest->fCoinStart.isCoincident() && largest->fCoinEnd.i sCoincident();
578 while ((test = test->fNext)) {
579 bool testCoin = test->fCoinStart.isCoincident() || test->fCoinEnd.isCoin cident();
580 if ((largestCoin && !testCoin) || (largestCoin == testCoin
581 && (largest->fBoundsMax < test->fBoundsMax
582 || (largest->fCollapsed && !test->fCollapsed)))) {
583 largest = test;
584 largestCoin = testCoin;
585 }
586 }
587 return largestCoin ? NULL : largest;
588 }
589
590 template<typename TCurve>
591 void SkTSect<TCurve>::coincidentCheck(SkTSect* sect2) {
592 SkTSpan<TCurve>* first = fHead;
593 SkTSpan<TCurve>* next;
594 do {
595 int consecutive = 1;
596 SkTSpan<TCurve>* last = first;
597 do {
598 next = last->fNext;
599 if (!next) {
600 break;
601 }
602 if (next->fStartT > last->fEndT) {
603 break;
604 }
605 ++consecutive;
606 last = next;
607 } while (true);
608 if (consecutive < COINCIDENT_SPAN_COUNT) {
609 continue;
610 }
611 setPerp(sect2->fCurve, first, last);
612 // check to see if a range of points are on the curve
613 onCurveCheck(sect2, first, last);
614 SkTSpan<TCurve>* removalCandidate = NULL;
615 if (!first->fCoinStart.isCoincident()) {
616 SkTSpan<TCurve>* firstCoin = first->fNext;
617 removalCandidate = first;
618 first = firstCoin;
619 }
620 if (!first->fCoinStart.isCoincident()) {
621 continue;
622 }
623 if (removalCandidate) {
624 removeSpans(removalCandidate, sect2);
625 }
626 if (!last->fCoinStart.isCoincident()) {
627 continue;
628 }
629 if (!last->fCoinEnd.isCoincident()) {
630 if (--consecutive < COINCIDENT_SPAN_COUNT) {
631 continue;
632 }
633 last = last->fPrev;
634 SkASSERT(last->fCoinStart.isCoincident());
635 SkASSERT(last->fCoinEnd.isCoincident());
636 }
637 SkASSERT(between(0, first->fCoinStart.perpT(), 1) || first->fCoinStart.p erpT() == -1);
638 if (first->fCoinStart.perpT() < 0) {
639 first->fCoinStart.setPerp(fCurve, first->fStartT, first->fPart[0], s ect2->fCurve);
640 }
641 SkASSERT(between(0, last->fCoinEnd.perpT(), 1) || last->fCoinEnd.perpT() == -1);
642 if (last->fCoinEnd.perpT() < 0) {
643 last->fCoinEnd.setPerp(fCurve, last->fEndT, last->fPart[TCurve::kPoi ntLast],
644 sect2->fCurve);
645 }
646 SkTSpan<TCurve>* removeMe = first->fNext;
647 while (removeMe != last) {
648 SkTSpan<TCurve>* removeNext = removeMe->fNext;
649 removeSpans(removeMe, sect2);
650 removeMe = removeNext;
651 }
652 } while ((first = next));
653 }
654
655 template<typename TCurve>
656 bool SkTSect<TCurve>::intersects(SkTSpan<TCurve>* span, const SkTSect* opp,
657 const SkTSpan<TCurve>* oppSpan) const {
658 bool check; // we ignore whether the end points are in common or not
659 if (!span->intersects(oppSpan, &check)) {
660 return false;
661 }
662 if (fActiveCount < COINCIDENT_SPAN_COUNT || opp->fActiveCount < COINCIDENT_S PAN_COUNT) {
663 return true;
664 }
665 return span->tightBoundsIntersects(oppSpan);
666 }
667
668 template<typename TCurve>
669 void SkTSect<TCurve>::onCurveCheck(SkTSect* sect2, SkTSpan<TCurve>* first, SkTSp an<TCurve>* last) {
670 SkTSpan<TCurve>* work = first;
671 first = NULL;
672 do {
673 if (work->fCoinStart.isCoincident()) {
674 if (!first) {
675 first = work;
676 }
677 } else if (first) {
678 break;
679 }
680 if (work == last) {
681 break;
682 }
683 work = work->fNext;
684 SkASSERT(work);
685 } while (true);
686 if (!first) {
687 return;
688 }
689 // march outwards to find limit of coincidence from here to previous and nex t spans
690 double startT = first->fStartT;
691 double oppT;
692 SkTSpan<TCurve>* prev = first->fPrev;
693 if (prev) {
694 double coinStart;
695 if (binarySearchCoin(*sect2, startT, prev->fStartT - startT, &coinStart, &oppT)) {
696 if (coinStart < startT) {
697 SkASSERT(prev->fStartT < coinStart && coinStart < prev->fEndT);
698 SkTSpan<TCurve>* oppStart = sect2->fHead->find(oppT);
699 if (oppStart->fStartT < oppT && oppT < oppStart->fEndT) {
700 // split prev at coinStart if needed
701 SkTSpan<TCurve>* half2 = addOne();
702 half2->splitAt(prev, coinStart);
703 half2->initBounds(fCurve);
704 prev->initBounds(fCurve);
705 prev->fCoinEnd.markCoincident();
706 half2->fCoinStart.markCoincident();
707 half2->fCoinEnd.markCoincident();
708 // find span containing opposite t, and split that too
709 SkTSpan<TCurve>* oppHalf = sect2->addOne();
710 oppHalf->splitAt(oppStart, oppT);
711 oppHalf->initBounds(sect2->fCurve);
712 oppStart->initBounds(sect2->fCurve);
713 } else {
714 SkASSERT(oppStart->fStartT == oppT || oppT == oppStart->fEnd T);
715 first->fStartT = coinStart;
716 prev->fEndT = coinStart;
717 first->initBounds(fCurve);
718 prev->initBounds(fCurve);
719 first->fCoinStart.markCoincident();
720 first->fCoinEnd.markCoincident();
721 }
722 }
723 }
724 }
725 if (!work->fCoinEnd.isCoincident()) {
726 if (work->fEndT == 1) {
727 SkDebugf("!");
728 }
729 // SkASSERT(work->fEndT < 1);
730 startT = work->fStartT;
731 double coinEnd;
732 if (binarySearchCoin(*sect2, startT, work->fEndT - startT, &coinEnd, &op pT)) {
733 if (coinEnd > startT) {
734 SkTSpan<TCurve>* oppStart = sect2->fHead->find(oppT);
735 if (oppStart->fStartT < oppT && oppT < oppStart->fEndT) {
736 SkASSERT(coinEnd < work->fEndT);
737 // split prev at coinEnd if needed
738 SkTSpan<TCurve>* half2 = addOne();
739 half2->splitAt(work, coinEnd);
740 half2->initBounds(fCurve);
741 work->initBounds(fCurve);
742 work->fCoinStart.markCoincident();
743 work->fCoinEnd.markCoincident();
744 half2->fCoinStart.markCoincident();
745 SkTSpan<TCurve>* oppHalf = sect2->addOne();
746 oppHalf->splitAt(oppStart, oppT);
747 oppHalf->initBounds(sect2->fCurve);
748 oppStart->initBounds(sect2->fCurve);
749 } else {
750 SkASSERT(oppStart->fStartT == oppT || oppT == oppStart->fEnd T);
751 SkTSpan<TCurve>* next = work->fNext;
752 bool hasNext = next && work->fEndT == next->fStartT;
753 work->fEndT = coinEnd;
754 work->initBounds(fCurve);
755 work->fCoinStart.markCoincident();
756 work->fCoinEnd.markCoincident();
757 if (hasNext) {
758 next->fStartT = coinEnd;
759 next->initBounds(fCurve);
760 }
761 }
762 }
763 }
764 }
765 }
766
767 template<typename TCurve>
768 void SkTSect<TCurve>::recoverCollapsed() {
769 SkTSpan<TCurve>* deleted = fDeleted;
770 while (deleted) {
771 SkTSpan<TCurve>* delNext = deleted->fNext;
772 if (deleted->fCollapsed) {
773 SkTSpan<TCurve>** spanPtr = &fHead;
774 while (*spanPtr && (*spanPtr)->fEndT <= deleted->fStartT) {
775 spanPtr = &(*spanPtr)->fNext;
776 }
777 deleted->fNext = *spanPtr;
778 *spanPtr = deleted;
779 }
780 deleted = delNext;
781 }
782 }
783
784 template<typename TCurve>
785 void SkTSect<TCurve>::removeSpan(SkTSpan<TCurve>* span) {
786 SkTSpan<TCurve>* prev = span->fPrev;
787 SkTSpan<TCurve>* next = span->fNext;
788 if (prev) {
789 prev->fNext = next;
790 if (next) {
791 next->fPrev = prev;
792 }
793 } else {
794 fHead = next;
795 if (next) {
796 next->fPrev = NULL;
797 }
798 }
799 --fActiveCount;
800 span->fNext = fDeleted;
801 fDeleted = span;
802 #if DEBUG_T_SECT
803 SkASSERT(!span->fDebugDeleted);
804 span->fDebugDeleted = true;
805 #endif
806 }
807
808 template<typename TCurve>
809 void SkTSect<TCurve>::removeOne(const SkTSpan<TCurve>* test, SkTSpan<TCurve>* sp an) {
810 int last = span->fBounded.count() - 1;
811 for (int index = 0; index <= last; ++index) {
812 if (span->fBounded[index] == test) {
813 span->fBounded.removeShuffle(index);
814 if (!last) {
815 removeSpan(span);
816 }
817 return;
818 }
819 }
820 }
821
822 template<typename TCurve>
823 void SkTSect<TCurve>::removeSpans(SkTSpan<TCurve>* span, SkTSect<TCurve>* opp) {
824 int count = span->fBounded.count();
825 for (int index = 0; index < count; ++index) {
826 SkTSpan<TCurve>* bounded = span->fBounded[0];
827 removeOne(bounded, span); // shuffles last into position 0
828 opp->removeOne(span, bounded);
829 }
830 }
831
832 template<typename TCurve>
833 void SkTSect<TCurve>::setPerp(const TCurve& opp, SkTSpan<TCurve>* first, SkTSpan <TCurve>* last) {
834 SkTSpan<TCurve>* work = first;
835 if (!work->fHasPerp) {
836 work->fCoinStart.setPerp(fCurve, work->fStartT, work->fPart[0], opp);
837 }
838 do {
839 if (!work->fHasPerp) {
840 work->fCoinEnd.setPerp(fCurve, work->fEndT, work->fPart[TCurve::kPoi ntLast], opp);
841 work->fHasPerp = true;
842 }
843 if (work == last) {
844 break;
845 }
846 SkTSpan<TCurve>* last = work;
847 work = work->fNext;
848 SkASSERT(work);
849 if (!work->fHasPerp) {
850 work->fCoinStart = last->fCoinEnd;
851 }
852 } while (true);
853 }
854
855 template<typename TCurve>
856 const SkTSpan<TCurve>* SkTSect<TCurve>::tail() const {
857 const SkTSpan<TCurve>* result = fHead;
858 const SkTSpan<TCurve>* next = fHead;
859 while ((next = next->fNext)) {
860 if (next->fEndT > result->fEndT) {
861 result = next;
862 }
863 }
864 return result;
865 }
866
867 /* Each span has a range of opposite spans it intersects. After the span is spli t in two,
868 adjust the range to its new size */
869 template<typename TCurve>
870 void SkTSect<TCurve>::trim(SkTSpan<TCurve>* span, SkTSect* opp) {
871 span->initBounds(fCurve);
872 int count = span->fBounded.count();
873 for (int index = 0; index < count; ) {
874 SkTSpan<TCurve>* test = span->fBounded[index];
875 bool sects = intersects(span, opp, test);
876 if (sects) {
877 ++index;
878 } else {
879 removeOne(test, span);
880 opp->removeOne(span, test);
881 --count;
882 }
883 }
884 }
885
886 #if DEBUG_T_SECT
887 template<typename TCurve>
888 void SkTSect<TCurve>::validate() const {
889 int count = 0;
890 if (fHead) {
891 const SkTSpan<TCurve>* span = fHead;
892 SkASSERT(!span->fPrev);
893 double last = 0;
894 do {
895 span->validate();
896 SkASSERT(span->fStartT >= last);
897 last = span->fEndT;
898 ++count;
899 } while ((span = span->fNext) != NULL);
900 }
901 SkASSERT(count == fActiveCount);
902 SkASSERT(fActiveCount <= fDebugAllocatedCount);
903 int deletedCount = 0;
904 const SkTSpan<TCurve>* deleted = fDeleted;
905 while (deleted) {
906 ++deletedCount;
907 deleted = deleted->fNext;
908 }
909 SkASSERT(fActiveCount + deletedCount == fDebugAllocatedCount);
910 }
911 #endif
912
913 template<typename TCurve>
914 int SkTSect<TCurve>::EndsEqual(const SkTSect* sect1, const SkTSect* sect2,
915 SkIntersections* intersections) {
916 int zeroOneSet = 0;
917 // check for zero
918 if (sect1->fCurve[0].approximatelyEqual(sect2->fCurve[0])) {
919 zeroOneSet |= kZeroS1Set | kZeroS2Set;
920 if (sect1->fCurve[0] != sect2->fCurve[0]) {
921 intersections->insertNear(0, 0, sect1->fCurve[0], sect2->fCurve[0]);
922 } else {
923 intersections->insert(0, 0, sect1->fCurve[0]);
924 }
925 }
926 if (sect1->fCurve[0].approximatelyEqual(sect2->fCurve[TCurve::kPointLast])) {
927 zeroOneSet |= kZeroS1Set | kOneS2Set;
928 if (sect1->fCurve[0] != sect2->fCurve[TCurve::kPointLast]) {
929 intersections->insertNear(0, 1, sect1->fCurve[0], sect2->fCurve[TCur ve::kPointLast]);
930 } else {
931 intersections->insert(0, 1, sect1->fCurve[0]);
932 }
933 }
934 // check for one
935 if (sect1->fCurve[TCurve::kPointLast].approximatelyEqual(sect2->fCurve[0])) {
936 zeroOneSet |= kOneS1Set | kZeroS2Set;
937 if (sect1->fCurve[TCurve::kPointLast] != sect2->fCurve[0]) {
938 intersections->insertNear(1, 0, sect1->fCurve[TCurve::kPointLast], s ect2->fCurve[0]);
939 } else {
940 intersections->insert(1, 0, sect1->fCurve[TCurve::kPointLast]);
941 }
942 }
943 if (sect1->fCurve[TCurve::kPointLast].approximatelyEqual(sect2->fCurve[TCurv e::kPointLast])) {
944 zeroOneSet |= kOneS1Set | kOneS2Set;
945 if (sect1->fCurve[TCurve::kPointLast] != sect2->fCurve[TCurve::kPointLas t]) {
946 intersections->insertNear(1, 1, sect1->fCurve[TCurve::kPointLast],
947 sect2->fCurve[TCurve::kPointLast]);
948 } else {
949 intersections->insert(1, 1, sect1->fCurve[TCurve::kPointLast]);
950 }
951 }
952 return zeroOneSet;
953 }
954
955 template<typename TCurve>
956 struct SkClosestRecord {
957 void addIntersection(SkIntersections* intersections) const {
958 double r1t = fC1Index ? fC1Span->endT() : fC1Span->startT();
959 double r2t = fC2Index ? fC2Span->endT() : fC2Span->startT();
960 intersections->insert(r1t, r2t, fC1Span->part()[fC1Index]);
961 }
962
963 void findEnd(const SkTSpan<TCurve>* span1, const SkTSpan<TCurve>* span2,
964 int c1Index, int c2Index) {
965 const TCurve& c1 = span1->part();
966 const TCurve& c2 = span2->part();
967 if (!c1[c1Index].approximatelyEqual(c2[c2Index])) {
968 return;
969 }
970 double dist = c1[c1Index].distanceSquared(c2[c2Index]);
971 if (fClosest < dist) {
972 return;
973 }
974 fC1Span = span1;
975 fC2Span = span2;
976 fC1StartT = span1->startT();
977 fC1EndT = span1->endT();
978 fC2StartT = span2->startT();
979 fC2EndT = span2->endT();
980 fC1Index = c1Index;
981 fC2Index = c2Index;
982 fClosest = dist;
983 }
984
985 bool matesWith(const SkClosestRecord& mate) const {
986 SkASSERT(fC1Span == mate.fC1Span || fC1Span->endT() <= mate.fC1Span->sta rtT()
987 || mate.fC1Span->endT() <= fC1Span->startT());
988 SkASSERT(fC2Span == mate.fC2Span || fC2Span->endT() <= mate.fC2Span->sta rtT()
989 || mate.fC2Span->endT() <= fC2Span->startT());
990 return fC1Span == mate.fC1Span || fC1Span->endT() == mate.fC1Span->start T()
991 || fC1Span->startT() == mate.fC1Span->endT()
992 || fC2Span == mate.fC2Span
993 || fC2Span->endT() == mate.fC2Span->startT()
994 || fC2Span->startT() == mate.fC2Span->endT();
995 }
996
997 void merge(const SkClosestRecord& mate) {
998 fC1Span = mate.fC1Span;
999 fC2Span = mate.fC2Span;
1000 fClosest = mate.fClosest;
1001 fC1Index = mate.fC1Index;
1002 fC2Index = mate.fC2Index;
1003 }
1004
1005 void reset() {
1006 fClosest = FLT_MAX;
1007 SkDEBUGCODE(fC1Span = fC2Span = NULL);
1008 SkDEBUGCODE(fC1Index = fC2Index = -1);
1009 }
1010
1011 void update(const SkClosestRecord& mate) {
1012 fC1StartT = SkTMin(fC1StartT, mate.fC1StartT);
1013 fC1EndT = SkTMax(fC1EndT, mate.fC1EndT);
1014 fC2StartT = SkTMin(fC2StartT, mate.fC2StartT);
1015 fC2EndT = SkTMax(fC2EndT, mate.fC2EndT);
1016 }
1017
1018 const SkTSpan<TCurve>* fC1Span;
1019 const SkTSpan<TCurve>* fC2Span;
1020 double fC1StartT;
1021 double fC1EndT;
1022 double fC2StartT;
1023 double fC2EndT;
1024 double fClosest;
1025 int fC1Index;
1026 int fC2Index;
1027 };
1028
1029 template<typename TCurve>
1030 struct SkClosestSect {
1031 SkClosestSect()
1032 : fUsed(0) {
1033 fClosest.push_back().reset();
1034 }
1035
1036 void find(const SkTSpan<TCurve>* span1, const SkTSpan<TCurve>* span2) {
1037 SkClosestRecord<TCurve>* record = &fClosest[fUsed];
1038 record->findEnd(span1, span2, 0, 0);
1039 record->findEnd(span1, span2, 0, TCurve::kPointLast);
1040 record->findEnd(span1, span2, TCurve::kPointLast, 0);
1041 record->findEnd(span1, span2, TCurve::kPointLast, TCurve::kPointLast);
1042 if (record->fClosest == FLT_MAX) {
1043 return;
1044 }
1045 for (int index = 0; index < fUsed; ++index) {
1046 SkClosestRecord<TCurve>* test = &fClosest[index];
1047 if (test->matesWith(*record)) {
1048 if (test->fClosest > record->fClosest) {
1049 test->merge(*record);
1050 }
1051 test->update(*record);
1052 record->reset();
1053 return;
1054 }
1055 }
1056 ++fUsed;
1057 fClosest.push_back().reset();
1058 }
1059
1060 void finish(SkIntersections* intersections) const {
1061 for (int index = 0; index < fUsed; ++index) {
1062 const SkClosestRecord<TCurve>& test = fClosest[index];
1063 test.addIntersection(intersections);
1064 }
1065 }
1066
1067 // this is oversized by one so that an extra record can merge into final one
1068 SkSTArray<TCurve::kMaxIntersections + 1, SkClosestRecord<TCurve>, true> fClo sest;
1069 int fUsed;
1070 };
1071
1072 // returns true if the rect is too small to consider
1073 template<typename TCurve>
1074 void SkTSect<TCurve>::BinarySearch(SkTSect* sect1, SkTSect* sect2, SkIntersectio ns* intersections) {
1075 intersections->reset();
1076 intersections->setMax(TCurve::kMaxIntersections);
1077 SkTSpan<TCurve>* span1 = sect1->fHead;
1078 SkTSpan<TCurve>* span2 = sect2->fHead;
1079 bool check;
1080 if (!span1->intersects(span2, &check)) {
1081 return;
1082 }
1083 if (check) {
1084 (void) EndsEqual(sect1, sect2, intersections);
1085 return;
1086 }
1087 span1->fBounded.push_back() = span2;
1088 span2->fBounded.push_back() = span1;
1089 do {
1090 // find the largest bounds
1091 SkTSpan<TCurve>* largest1 = sect1->boundsMax();
1092 if (!largest1) {
1093 break;
1094 }
1095 SkTSpan<TCurve>* largest2 = sect2->boundsMax();
1096 bool split1 = !largest2 || (largest1 && (largest1->fBoundsMax > largest2 ->fBoundsMax
1097 || (!largest1->fCollapsed && largest2->fCollapsed)));
1098 // split it
1099 SkTSect* splitSect = split1 ? sect1 : sect2;
1100 SkTSpan<TCurve>* half1 = split1 ? largest1 : largest2;
1101 SkASSERT(half1);
1102 if (half1->fCollapsed) {
1103 break;
1104 }
1105 // trim parts that don't intersect the opposite
1106 SkTSpan<TCurve>* half2 = splitSect->addOne();
1107 SkTSect* unsplitSect = split1 ? sect2 : sect1;
1108 if (!half2->split(half1)) {
1109 break;
1110 }
1111 splitSect->trim(half1, unsplitSect);
1112 splitSect->trim(half2, unsplitSect);
1113 // if there are 9 or more continuous spans on both sects, suspect coinci dence
1114 if (sect1->fActiveCount >= COINCIDENT_SPAN_COUNT
1115 && sect2->fActiveCount >= COINCIDENT_SPAN_COUNT) {
1116 sect1->coincidentCheck(sect2);
1117 }
1118 #if DEBUG_T_SECT
1119 sect1->validate();
1120 sect2->validate();
1121 #endif
1122 #if DEBUG_T_SECT_DUMP > 1
1123 sect1->dumpBoth(*sect2);
1124 #endif
1125 if (!sect1->fHead || !sect2->fHead) {
1126 return;
1127 }
1128 } while (true);
1129 if (sect1->fActiveCount >= 2 && sect2->fActiveCount >= 2) {
1130 // check for coincidence
1131 SkTSpan<TCurve>* first = sect1->fHead;
1132 do {
1133 if (!first->fCoinStart.isCoincident()) {
1134 continue;
1135 }
1136 int spanCount = 1;
1137 SkTSpan<TCurve>* last = first;
1138 while (last->fCoinEnd.isCoincident()) {
1139 SkTSpan<TCurve>* next = last->fNext;
1140 if (!next || !next->fCoinEnd.isCoincident()) {
1141 break;
1142 }
1143 last = next;
1144 ++spanCount;
1145 }
1146 if (spanCount < 2) {
1147 first = last;
1148 continue;
1149 }
1150 int index = intersections->insertCoincident(first->fStartT, first->f CoinStart.perpT(),
1151 first->fPart[0]);
1152 if (intersections->insertCoincident(last->fEndT, last->fCoinEnd.perp T(),
1153 last->fPart[TCurve::kPointLast]) < 0) {
1154 intersections->clearCoincidence(index);
1155 }
1156 } while ((first = first->fNext));
1157 }
1158 int zeroOneSet = EndsEqual(sect1, sect2, intersections);
1159 sect1->recoverCollapsed();
1160 sect2->recoverCollapsed();
1161 SkTSpan<TCurve>* result1 = sect1->fHead;
1162 // check heads and tails for zero and ones and insert them if we haven't alr eady done so
1163 const SkTSpan<TCurve>* head1 = result1;
1164 if (!(zeroOneSet & kZeroS1Set) && approximately_less_than_zero(head1->fStart T)) {
1165 const SkDPoint& start1 = sect1->fCurve[0];
1166 double t = head1->closestBoundedT(start1);
1167 if (sect2->fCurve.ptAtT(t).approximatelyEqual(start1)) {
1168 intersections->insert(0, t, start1);
1169 }
1170 }
1171 const SkTSpan<TCurve>* head2 = sect2->fHead;
1172 if (!(zeroOneSet & kZeroS2Set) && approximately_less_than_zero(head2->fStart T)) {
1173 const SkDPoint& start2 = sect2->fCurve[0];
1174 double t = head2->closestBoundedT(start2);
1175 if (sect1->fCurve.ptAtT(t).approximatelyEqual(start2)) {
1176 intersections->insert(t, 0, start2);
1177 }
1178 }
1179 const SkTSpan<TCurve>* tail1 = sect1->tail();
1180 if (!(zeroOneSet & kOneS1Set) && approximately_greater_than_one(tail1->fEndT )) {
1181 const SkDPoint& end1 = sect1->fCurve[TCurve::kPointLast];
1182 double t = tail1->closestBoundedT(end1);
1183 if (sect2->fCurve.ptAtT(t).approximatelyEqual(end1)) {
1184 intersections->insert(1, t, end1);
1185 }
1186 }
1187 const SkTSpan<TCurve>* tail2 = sect2->tail();
1188 if (!(zeroOneSet & kOneS2Set) && approximately_greater_than_one(tail2->fEndT )) {
1189 const SkDPoint& end2 = sect2->fCurve[TCurve::kPointLast];
1190 double t = tail2->closestBoundedT(end2);
1191 if (sect1->fCurve.ptAtT(t).approximatelyEqual(end2)) {
1192 intersections->insert(t, 1, end2);
1193 }
1194 }
1195 SkClosestSect<TCurve> closest;
1196 do {
1197 while (result1 && result1->fCoinStart.isCoincident() && result1->fCoinEn d.isCoincident()) {
1198 result1 = result1->fNext;
1199 }
1200 if (!result1) {
1201 break;
1202 }
1203 SkTSpan<TCurve>* result2 = sect2->fHead;
1204 while (result2) {
1205 closest.find(result1, result2);
1206 result2 = result2->fNext;
1207 }
1208
1209 } while ((result1 = result1->fNext));
1210 closest.finish(intersections);
1211 }
OLDNEW
« no previous file with comments | « src/pathops/SkPathOpsTQuadSect.cpp ('k') | tests/PathOpsBuildUseTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698