Line data Source code
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 : #ifndef SkPathOpsTSect_DEFINED
8 : #define SkPathOpsTSect_DEFINED
9 :
10 : #include "SkArenaAlloc.h"
11 : #include "SkPathOpsBounds.h"
12 : #include "SkPathOpsRect.h"
13 : #include "SkIntersections.h"
14 : #include "SkTSort.h"
15 :
16 : #ifdef SK_DEBUG
17 : typedef uint8_t SkOpDebugBool;
18 : #else
19 : typedef bool SkOpDebugBool;
20 : #endif
21 :
22 : /* TCurve and OppCurve are one of { SkDQuadratic, SkDConic, SkDCubic } */
23 : template<typename TCurve, typename OppCurve>
24 : class SkTCoincident {
25 : public:
26 0 : SkTCoincident() {
27 0 : this->init();
28 0 : }
29 :
30 0 : void debugInit() {
31 : #ifdef SK_DEBUG
32 0 : this->fPerpPt.fX = this->fPerpPt.fY = SK_ScalarNaN;
33 0 : this->fPerpT = SK_ScalarNaN;
34 0 : this->fMatch = 0xFF;
35 : #endif
36 0 : }
37 :
38 : char dumpIsCoincidentStr() const;
39 : void dump() const;
40 :
41 0 : bool isMatch() const {
42 0 : SkASSERT(!!fMatch == fMatch);
43 0 : return SkToBool(fMatch);
44 : }
45 :
46 0 : void init() {
47 0 : fPerpT = -1;
48 0 : fMatch = false;
49 0 : fPerpPt.fX = fPerpPt.fY = SK_ScalarNaN;
50 0 : }
51 :
52 0 : void markCoincident() {
53 0 : if (!fMatch) {
54 0 : fPerpT = -1;
55 : }
56 0 : fMatch = true;
57 0 : }
58 :
59 0 : const SkDPoint& perpPt() const {
60 0 : return fPerpPt;
61 : }
62 :
63 0 : double perpT() const {
64 0 : return fPerpT;
65 : }
66 :
67 : void setPerp(const TCurve& c1, double t, const SkDPoint& cPt, const OppCurve& );
68 :
69 : private:
70 : SkDPoint fPerpPt;
71 : double fPerpT; // perpendicular intersection on opposite curve
72 : SkOpDebugBool fMatch;
73 : };
74 :
75 : template<typename TCurve, typename OppCurve> class SkTSect;
76 : template<typename TCurve, typename OppCurve> class SkTSpan;
77 :
78 : template<typename TCurve, typename OppCurve>
79 : struct SkTSpanBounded {
80 : SkTSpan<TCurve, OppCurve>* fBounded;
81 : SkTSpanBounded* fNext;
82 : };
83 :
84 : /* Curve is either TCurve or SkDCubic */
85 : template<typename TCurve, typename OppCurve>
86 0 : class SkTSpan {
87 : public:
88 : void addBounded(SkTSpan<OppCurve, TCurve>* , SkArenaAlloc* );
89 : double closestBoundedT(const SkDPoint& pt) const;
90 : bool contains(double t) const;
91 :
92 : void debugInit() {
93 : TCurve dummy;
94 : dummy.debugInit();
95 : init(dummy);
96 : initBounds(dummy);
97 : fCoinStart.init();
98 : fCoinEnd.init();
99 : }
100 :
101 : const SkTSect<OppCurve, TCurve>* debugOpp() const;
102 :
103 : #ifdef SK_DEBUG
104 0 : void debugSetGlobalState(SkOpGlobalState* state) {
105 0 : fDebugGlobalState = state;
106 0 : }
107 : #endif
108 :
109 : const SkTSpan* debugSpan(int ) const;
110 : const SkTSpan* debugT(double t) const;
111 : #ifdef SK_DEBUG
112 : bool debugIsBefore(const SkTSpan* span) const;
113 : #endif
114 : void dump() const;
115 : void dumpAll() const;
116 : void dumpBounded(int id) const;
117 : void dumpBounds() const;
118 : void dumpCoin() const;
119 :
120 0 : double endT() const {
121 0 : return fEndT;
122 : }
123 :
124 : SkTSpan<OppCurve, TCurve>* findOppSpan(const SkTSpan<OppCurve, TCurve>* opp) const;
125 :
126 0 : SkTSpan<OppCurve, TCurve>* findOppT(double t) const {
127 0 : SkTSpan<OppCurve, TCurve>* result = oppT(t);
128 0 : SkOPASSERT(result);
129 0 : return result;
130 : }
131 :
132 0 : SkDEBUGCODE(SkOpGlobalState* globalState() const { return fDebugGlobalState; })
133 :
134 0 : bool hasOppT(double t) const {
135 0 : return SkToBool(oppT(t));
136 : }
137 :
138 : int hullsIntersect(SkTSpan<OppCurve, TCurve>* span, bool* start, bool* oppStart);
139 : void init(const TCurve& );
140 : bool initBounds(const TCurve& );
141 :
142 0 : bool isBounded() const {
143 0 : return fBounded != nullptr;
144 : }
145 :
146 : bool linearsIntersect(SkTSpan<OppCurve, TCurve>* span);
147 : double linearT(const SkDPoint& ) const;
148 :
149 0 : void markCoincident() {
150 0 : fCoinStart.markCoincident();
151 0 : fCoinEnd.markCoincident();
152 0 : }
153 :
154 0 : const SkTSpan* next() const {
155 0 : return fNext;
156 : }
157 :
158 : bool onlyEndPointsInCommon(const SkTSpan<OppCurve, TCurve>* opp, bool* start,
159 : bool* oppStart, bool* ptsInCommon);
160 :
161 0 : const TCurve& part() const {
162 0 : return fPart;
163 : }
164 :
165 : bool removeAllBounded();
166 : bool removeBounded(const SkTSpan<OppCurve, TCurve>* opp);
167 :
168 0 : void reset() {
169 0 : fBounded = nullptr;
170 0 : }
171 :
172 0 : void resetBounds(const TCurve& curve) {
173 0 : fIsLinear = fIsLine = false;
174 0 : initBounds(curve);
175 0 : }
176 :
177 0 : bool split(SkTSpan* work, SkArenaAlloc* heap) {
178 0 : return splitAt(work, (work->fStartT + work->fEndT) * 0.5, heap);
179 : }
180 :
181 : bool splitAt(SkTSpan* work, double t, SkArenaAlloc* heap);
182 :
183 0 : double startT() const {
184 0 : return fStartT;
185 : }
186 :
187 : private:
188 :
189 : // implementation is for testing only
190 : int debugID() const {
191 : return PATH_OPS_DEBUG_T_SECT_RELEASE(fID, -1);
192 : }
193 :
194 : void dumpID() const;
195 :
196 : int hullCheck(const SkTSpan<OppCurve, TCurve>* opp, bool* start, bool* oppStart);
197 : int linearIntersects(const OppCurve& ) const;
198 : SkTSpan<OppCurve, TCurve>* oppT(double t) const;
199 :
200 : void validate() const;
201 : void validateBounded() const;
202 : void validatePerpT(double oppT) const;
203 : void validatePerpPt(double t, const SkDPoint& ) const;
204 :
205 : TCurve fPart;
206 : SkTCoincident<TCurve, OppCurve> fCoinStart;
207 : SkTCoincident<TCurve, OppCurve> fCoinEnd;
208 : SkTSpanBounded<OppCurve, TCurve>* fBounded;
209 : SkTSpan* fPrev;
210 : SkTSpan* fNext;
211 : SkDRect fBounds;
212 : double fStartT;
213 : double fEndT;
214 : double fBoundsMax;
215 : SkOpDebugBool fCollapsed;
216 : SkOpDebugBool fHasPerp;
217 : SkOpDebugBool fIsLinear;
218 : SkOpDebugBool fIsLine;
219 : SkOpDebugBool fDeleted;
220 : SkDEBUGCODE(SkOpGlobalState* fDebugGlobalState);
221 : SkDEBUGCODE(SkTSect<TCurve, OppCurve>* fDebugSect);
222 : PATH_OPS_DEBUG_T_SECT_CODE(int fID);
223 : friend class SkTSect<TCurve, OppCurve>;
224 : friend class SkTSect<OppCurve, TCurve>;
225 : friend class SkTSpan<OppCurve, TCurve>;
226 : };
227 :
228 : template<typename TCurve, typename OppCurve>
229 0 : class SkTSect {
230 : public:
231 : SkTSect(const TCurve& c SkDEBUGPARAMS(SkOpGlobalState* ) PATH_OPS_DEBUG_T_SECT_PARAMS(int id));
232 : static void BinarySearch(SkTSect* sect1, SkTSect<OppCurve, TCurve>* sect2,
233 : SkIntersections* intersections);
234 :
235 0 : SkDEBUGCODE(SkOpGlobalState* globalState() { return fDebugGlobalState; })
236 : // for testing only
237 : bool debugHasBounded(const SkTSpan<OppCurve, TCurve>* ) const;
238 :
239 : const SkTSect<OppCurve, TCurve>* debugOpp() const {
240 : return SkDEBUGRELEASE(fOppSect, nullptr);
241 : }
242 :
243 : const SkTSpan<TCurve, OppCurve>* debugSpan(int id) const;
244 : const SkTSpan<TCurve, OppCurve>* debugT(double t) const;
245 : void dump() const;
246 : void dumpBoth(SkTSect<OppCurve, TCurve>* ) const;
247 : void dumpBounded(int id) const;
248 : void dumpBounds() const;
249 : void dumpCoin() const;
250 : void dumpCoinCurves() const;
251 : void dumpCurves() const;
252 :
253 : private:
254 : enum {
255 : kZeroS1Set = 1,
256 : kOneS1Set = 2,
257 : kZeroS2Set = 4,
258 : kOneS2Set = 8
259 : };
260 :
261 : SkTSpan<TCurve, OppCurve>* addFollowing(SkTSpan<TCurve, OppCurve>* prior);
262 : void addForPerp(SkTSpan<OppCurve, TCurve>* span, double t);
263 : SkTSpan<TCurve, OppCurve>* addOne();
264 :
265 0 : SkTSpan<TCurve, OppCurve>* addSplitAt(SkTSpan<TCurve, OppCurve>* span, double t) {
266 0 : SkTSpan<TCurve, OppCurve>* result = this->addOne();
267 0 : SkDEBUGCODE(result->debugSetGlobalState(this->globalState()));
268 0 : result->splitAt(span, t, &fHeap);
269 0 : result->initBounds(fCurve);
270 0 : span->initBounds(fCurve);
271 0 : return result;
272 : }
273 :
274 : bool binarySearchCoin(SkTSect<OppCurve, TCurve>* , double tStart, double tStep, double* t,
275 : double* oppT);
276 : SkTSpan<TCurve, OppCurve>* boundsMax() const;
277 : bool coincidentCheck(SkTSect<OppCurve, TCurve>* sect2);
278 : void coincidentForce(SkTSect<OppCurve, TCurve>* sect2, double start1s, double start1e);
279 : bool coincidentHasT(double t);
280 : int collapsed() const;
281 : void computePerpendiculars(SkTSect<OppCurve, TCurve>* sect2, SkTSpan<TCurve, OppCurve>* first,
282 : SkTSpan<TCurve, OppCurve>* last);
283 : int countConsecutiveSpans(SkTSpan<TCurve, OppCurve>* first,
284 : SkTSpan<TCurve, OppCurve>** last) const;
285 :
286 : int debugID() const {
287 : return PATH_OPS_DEBUG_T_SECT_RELEASE(fID, -1);
288 : }
289 :
290 : bool deleteEmptySpans();
291 : void dumpCommon(const SkTSpan<TCurve, OppCurve>* ) const;
292 : void dumpCommonCurves(const SkTSpan<TCurve, OppCurve>* ) const;
293 : static int EndsEqual(const SkTSect* sect1, const SkTSect<OppCurve, TCurve>* sect2,
294 : SkIntersections* );
295 : bool extractCoincident(SkTSect<OppCurve, TCurve>* sect2, SkTSpan<TCurve, OppCurve>* first,
296 : SkTSpan<TCurve, OppCurve>* last, SkTSpan<TCurve, OppCurve>** result);
297 : SkTSpan<TCurve, OppCurve>* findCoincidentRun(SkTSpan<TCurve, OppCurve>* first,
298 : SkTSpan<TCurve, OppCurve>** lastPtr);
299 : int intersects(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp,
300 : SkTSpan<OppCurve, TCurve>* oppSpan, int* oppResult);
301 : bool isParallel(const SkDLine& thisLine, const SkTSect<OppCurve, TCurve>* opp) const;
302 : int linesIntersect(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp,
303 : SkTSpan<OppCurve, TCurve>* oppSpan, SkIntersections* );
304 : bool markSpanGone(SkTSpan<TCurve, OppCurve>* span);
305 : bool matchedDirection(double t, const SkTSect<OppCurve, TCurve>* sect2, double t2) const;
306 : void matchedDirCheck(double t, const SkTSect<OppCurve, TCurve>* sect2, double t2,
307 : bool* calcMatched, bool* oppMatched) const;
308 : void mergeCoincidence(SkTSect<OppCurve, TCurve>* sect2);
309 : SkTSpan<TCurve, OppCurve>* prev(SkTSpan<TCurve, OppCurve>* ) const;
310 : void removeByPerpendicular(SkTSect<OppCurve, TCurve>* opp);
311 : void recoverCollapsed();
312 : void removeCoincident(SkTSpan<TCurve, OppCurve>* span, bool isBetween);
313 : void removeAllBut(const SkTSpan<OppCurve, TCurve>* keep, SkTSpan<TCurve, OppCurve>* span,
314 : SkTSect<OppCurve, TCurve>* opp);
315 : bool removeSpan(SkTSpan<TCurve, OppCurve>* span);
316 : void removeSpanRange(SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>* last);
317 : void removeSpans(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp);
318 : void removedEndCheck(SkTSpan<TCurve, OppCurve>* span);
319 :
320 0 : void resetRemovedEnds() {
321 0 : fRemovedStartT = fRemovedEndT = false;
322 0 : }
323 :
324 : SkTSpan<TCurve, OppCurve>* spanAtT(double t, SkTSpan<TCurve, OppCurve>** priorSpan);
325 : SkTSpan<TCurve, OppCurve>* tail();
326 : bool trim(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp);
327 : void unlinkSpan(SkTSpan<TCurve, OppCurve>* span);
328 : bool updateBounded(SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>* last,
329 : SkTSpan<OppCurve, TCurve>* oppFirst);
330 : void validate() const;
331 : void validateBounded() const;
332 :
333 : const TCurve& fCurve;
334 : SkArenaAlloc fHeap;
335 : SkTSpan<TCurve, OppCurve>* fHead;
336 : SkTSpan<TCurve, OppCurve>* fCoincident;
337 : SkTSpan<TCurve, OppCurve>* fDeleted;
338 : int fActiveCount;
339 : bool fRemovedStartT;
340 : bool fRemovedEndT;
341 : SkDEBUGCODE(SkOpGlobalState* fDebugGlobalState);
342 : SkDEBUGCODE(SkTSect<OppCurve, TCurve>* fOppSect);
343 : PATH_OPS_DEBUG_T_SECT_CODE(int fID);
344 : PATH_OPS_DEBUG_T_SECT_CODE(int fDebugCount);
345 : #if DEBUG_T_SECT
346 : int fDebugAllocatedCount;
347 : #endif
348 : friend class SkTSpan<TCurve, OppCurve>;
349 : friend class SkTSpan<OppCurve, TCurve>;
350 : friend class SkTSect<OppCurve, TCurve>;
351 : };
352 :
353 : #define COINCIDENT_SPAN_COUNT 9
354 :
355 : template<typename TCurve, typename OppCurve>
356 0 : void SkTCoincident<TCurve, OppCurve>::setPerp(const TCurve& c1, double t,
357 : const SkDPoint& cPt, const OppCurve& c2) {
358 0 : SkDVector dxdy = c1.dxdyAtT(t);
359 0 : SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
360 0 : SkIntersections i SkDEBUGCODE((c1.globalState()));
361 0 : int used = i.intersectRay(c2, perp);
362 : // only keep closest
363 0 : if (used == 0 || used == 3) {
364 0 : this->init();
365 0 : return;
366 : }
367 0 : fPerpT = i[0][0];
368 0 : fPerpPt = i.pt(0);
369 0 : SkASSERT(used <= 2);
370 0 : if (used == 2) {
371 0 : double distSq = (fPerpPt - cPt).lengthSquared();
372 0 : double dist2Sq = (i.pt(1) - cPt).lengthSquared();
373 0 : if (dist2Sq < distSq) {
374 0 : fPerpT = i[0][1];
375 0 : fPerpPt = i.pt(1);
376 : }
377 : }
378 : #if DEBUG_T_SECT
379 : SkDebugf("setPerp t=%1.9g cPt=(%1.9g,%1.9g) %s oppT=%1.9g fPerpPt=(%1.9g,%1.9g)\n",
380 : t, cPt.fX, cPt.fY,
381 : cPt.approximatelyEqual(fPerpPt) ? "==" : "!=", fPerpT, fPerpPt.fX, fPerpPt.fY);
382 : #endif
383 0 : fMatch = cPt.approximatelyEqual(fPerpPt);
384 : #if DEBUG_T_SECT
385 : if (fMatch) {
386 : SkDebugf(""); // allow setting breakpoint
387 : }
388 : #endif
389 : }
390 :
391 : template<typename TCurve, typename OppCurve>
392 0 : void SkTSpan<TCurve, OppCurve>::addBounded(SkTSpan<OppCurve, TCurve>* span, SkArenaAlloc* heap) {
393 0 : SkTSpanBounded<OppCurve, TCurve>* bounded = heap->make<SkTSpanBounded<OppCurve, TCurve>>();
394 0 : bounded->fBounded = span;
395 0 : bounded->fNext = fBounded;
396 0 : fBounded = bounded;
397 0 : }
398 :
399 : template<typename TCurve, typename OppCurve>
400 0 : SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::addFollowing(
401 : SkTSpan<TCurve, OppCurve>* prior) {
402 0 : SkTSpan<TCurve, OppCurve>* result = this->addOne();
403 0 : SkDEBUGCODE(result->debugSetGlobalState(this->globalState()));
404 0 : result->fStartT = prior ? prior->fEndT : 0;
405 0 : SkTSpan<TCurve, OppCurve>* next = prior ? prior->fNext : fHead;
406 0 : result->fEndT = next ? next->fStartT : 1;
407 0 : result->fPrev = prior;
408 0 : result->fNext = next;
409 0 : if (prior) {
410 0 : prior->fNext = result;
411 : } else {
412 0 : fHead = result;
413 : }
414 0 : if (next) {
415 0 : next->fPrev = result;
416 : }
417 0 : result->resetBounds(fCurve);
418 0 : result->validate();
419 0 : return result;
420 : }
421 :
422 : template<typename TCurve, typename OppCurve>
423 0 : void SkTSect<TCurve, OppCurve>::addForPerp(SkTSpan<OppCurve, TCurve>* span, double t) {
424 0 : if (!span->hasOppT(t)) {
425 : SkTSpan<TCurve, OppCurve>* priorSpan;
426 0 : SkTSpan<TCurve, OppCurve>* opp = this->spanAtT(t, &priorSpan);
427 0 : if (!opp) {
428 0 : opp = this->addFollowing(priorSpan);
429 : #if DEBUG_PERP
430 : SkDebugf("%s priorSpan=%d t=%1.9g opp=%d\n", __FUNCTION__, priorSpan ?
431 : priorSpan->debugID() : -1, t, opp->debugID());
432 : #endif
433 : }
434 : #if DEBUG_PERP
435 : opp->dump(); SkDebugf("\n");
436 : SkDebugf("%s addBounded span=%d opp=%d\n", __FUNCTION__, priorSpan ?
437 : priorSpan->debugID() : -1, opp->debugID());
438 : #endif
439 0 : opp->addBounded(span, &fHeap);
440 0 : span->addBounded(opp, &fHeap);
441 : }
442 0 : this->validate();
443 : #if DEBUG_T_SECT
444 : span->validatePerpT(t);
445 : #endif
446 0 : }
447 :
448 : template<typename TCurve, typename OppCurve>
449 0 : double SkTSpan<TCurve, OppCurve>::closestBoundedT(const SkDPoint& pt) const {
450 0 : double result = -1;
451 0 : double closest = DBL_MAX;
452 0 : const SkTSpanBounded<OppCurve, TCurve>* testBounded = fBounded;
453 0 : while (testBounded) {
454 0 : const SkTSpan<OppCurve, TCurve>* test = testBounded->fBounded;
455 0 : double startDist = test->fPart[0].distanceSquared(pt);
456 0 : if (closest > startDist) {
457 0 : closest = startDist;
458 0 : result = test->fStartT;
459 : }
460 0 : double endDist = test->fPart[OppCurve::kPointLast].distanceSquared(pt);
461 0 : if (closest > endDist) {
462 0 : closest = endDist;
463 0 : result = test->fEndT;
464 : }
465 0 : testBounded = testBounded->fNext;
466 : }
467 0 : SkASSERT(between(0, result, 1));
468 0 : return result;
469 : }
470 :
471 : #ifdef SK_DEBUG
472 : template<typename TCurve, typename OppCurve>
473 : bool SkTSpan<TCurve, OppCurve>::debugIsBefore(const SkTSpan* span) const {
474 : const SkTSpan* work = this;
475 : do {
476 : if (span == work) {
477 : return true;
478 : }
479 : } while ((work = work->fNext));
480 : return false;
481 : }
482 : #endif
483 :
484 : template<typename TCurve, typename OppCurve>
485 0 : bool SkTSpan<TCurve, OppCurve>::contains(double t) const {
486 0 : const SkTSpan* work = this;
487 0 : do {
488 0 : if (between(work->fStartT, t, work->fEndT)) {
489 0 : return true;
490 : }
491 : } while ((work = work->fNext));
492 0 : return false;
493 : }
494 :
495 : template<typename TCurve, typename OppCurve>
496 : const SkTSect<OppCurve, TCurve>* SkTSpan<TCurve, OppCurve>::debugOpp() const {
497 : return SkDEBUGRELEASE(fDebugSect->debugOpp(), nullptr);
498 : }
499 :
500 : template<typename TCurve, typename OppCurve>
501 0 : SkTSpan<OppCurve, TCurve>* SkTSpan<TCurve, OppCurve>::findOppSpan(
502 : const SkTSpan<OppCurve, TCurve>* opp) const {
503 0 : SkTSpanBounded<OppCurve, TCurve>* bounded = fBounded;
504 0 : while (bounded) {
505 0 : SkTSpan<OppCurve, TCurve>* test = bounded->fBounded;
506 0 : if (opp == test) {
507 0 : return test;
508 : }
509 0 : bounded = bounded->fNext;
510 : }
511 0 : return nullptr;
512 : }
513 :
514 : // returns 0 if no hull intersection
515 : // 1 if hulls intersect
516 : // 2 if hulls only share a common endpoint
517 : // -1 if linear and further checking is required
518 : template<typename TCurve, typename OppCurve>
519 0 : int SkTSpan<TCurve, OppCurve>::hullCheck(const SkTSpan<OppCurve, TCurve>* opp,
520 : bool* start, bool* oppStart) {
521 0 : if (fIsLinear) {
522 0 : return -1;
523 : }
524 : bool ptsInCommon;
525 0 : if (onlyEndPointsInCommon(opp, start, oppStart, &ptsInCommon)) {
526 0 : SkASSERT(ptsInCommon);
527 0 : return 2;
528 : }
529 : bool linear;
530 0 : if (fPart.hullIntersects(opp->fPart, &linear)) {
531 0 : if (!linear) { // check set true if linear
532 0 : return 1;
533 : }
534 0 : fIsLinear = true;
535 0 : fIsLine = fPart.controlsInside();
536 0 : return ptsInCommon ? 1 : -1;
537 : } else { // hull is not linear; check set true if intersected at the end points
538 0 : return ((int) ptsInCommon) << 1; // 0 or 2
539 : }
540 : return 0;
541 : }
542 :
543 : // OPTIMIZE ? If at_most_end_pts_in_common detects that one quad is near linear,
544 : // use line intersection to guess a better split than 0.5
545 : // OPTIMIZE Once at_most_end_pts_in_common detects linear, mark span so all future splits are linear
546 : template<typename TCurve, typename OppCurve>
547 0 : int SkTSpan<TCurve, OppCurve>::hullsIntersect(SkTSpan<OppCurve, TCurve>* opp,
548 : bool* start, bool* oppStart) {
549 0 : if (!fBounds.intersects(opp->fBounds)) {
550 0 : return 0;
551 : }
552 0 : int hullSect = this->hullCheck(opp, start, oppStart);
553 0 : if (hullSect >= 0) {
554 0 : return hullSect;
555 : }
556 0 : hullSect = opp->hullCheck(this, oppStart, start);
557 0 : if (hullSect >= 0) {
558 0 : return hullSect;
559 : }
560 0 : return -1;
561 : }
562 :
563 : template<typename TCurve, typename OppCurve>
564 0 : void SkTSpan<TCurve, OppCurve>::init(const TCurve& c) {
565 0 : fPrev = fNext = nullptr;
566 0 : fStartT = 0;
567 0 : fEndT = 1;
568 0 : fBounded = nullptr;
569 0 : resetBounds(c);
570 0 : }
571 :
572 : template<typename TCurve, typename OppCurve>
573 0 : bool SkTSpan<TCurve, OppCurve>::initBounds(const TCurve& c) {
574 0 : fPart = c.subDivide(fStartT, fEndT);
575 0 : fBounds.setBounds(fPart);
576 0 : fCoinStart.init();
577 0 : fCoinEnd.init();
578 0 : fBoundsMax = SkTMax(fBounds.width(), fBounds.height());
579 0 : fCollapsed = fPart.collapsed();
580 0 : fHasPerp = false;
581 0 : fDeleted = false;
582 : #if DEBUG_T_SECT
583 : if (fCollapsed) {
584 : SkDebugf(""); // for convenient breakpoints
585 : }
586 : #endif
587 0 : return fBounds.valid();
588 : }
589 :
590 : template<typename TCurve, typename OppCurve>
591 0 : bool SkTSpan<TCurve, OppCurve>::linearsIntersect(SkTSpan<OppCurve, TCurve>* span) {
592 0 : int result = this->linearIntersects(span->fPart);
593 0 : if (result <= 1) {
594 0 : return SkToBool(result);
595 : }
596 0 : SkASSERT(span->fIsLinear);
597 0 : result = span->linearIntersects(this->fPart);
598 : // SkASSERT(result <= 1);
599 0 : return SkToBool(result);
600 : }
601 :
602 : template<typename TCurve, typename OppCurve>
603 : double SkTSpan<TCurve, OppCurve>::linearT(const SkDPoint& pt) const {
604 : SkDVector len = fPart[TCurve::kPointLast] - fPart[0];
605 : return fabs(len.fX) > fabs(len.fY)
606 : ? (pt.fX - fPart[0].fX) / len.fX
607 : : (pt.fY - fPart[0].fY) / len.fY;
608 : }
609 :
610 : template<typename TCurve, typename OppCurve>
611 0 : int SkTSpan<TCurve, OppCurve>::linearIntersects(const OppCurve& q2) const {
612 : // looks like q1 is near-linear
613 0 : int start = 0, end = TCurve::kPointLast; // the outside points are usually the extremes
614 0 : if (!fPart.controlsInside()) {
615 0 : double dist = 0; // if there's any question, compute distance to find best outsiders
616 0 : for (int outer = 0; outer < TCurve::kPointCount - 1; ++outer) {
617 0 : for (int inner = outer + 1; inner < TCurve::kPointCount; ++inner) {
618 0 : double test = (fPart[outer] - fPart[inner]).lengthSquared();
619 0 : if (dist > test) {
620 0 : continue;
621 : }
622 0 : dist = test;
623 0 : start = outer;
624 0 : end = inner;
625 : }
626 : }
627 : }
628 : // see if q2 is on one side of the line formed by the extreme points
629 0 : double origX = fPart[start].fX;
630 0 : double origY = fPart[start].fY;
631 0 : double adj = fPart[end].fX - origX;
632 0 : double opp = fPart[end].fY - origY;
633 0 : double maxPart = SkTMax(fabs(adj), fabs(opp));
634 0 : double sign = 0; // initialization to shut up warning in release build
635 0 : for (int n = 0; n < OppCurve::kPointCount; ++n) {
636 0 : double dx = q2[n].fY - origY;
637 0 : double dy = q2[n].fX - origX;
638 0 : double maxVal = SkTMax(maxPart, SkTMax(fabs(dx), fabs(dy)));
639 0 : double test = (q2[n].fY - origY) * adj - (q2[n].fX - origX) * opp;
640 0 : if (precisely_zero_when_compared_to(test, maxVal)) {
641 0 : return 1;
642 : }
643 0 : if (approximately_zero_when_compared_to(test, maxVal)) {
644 0 : return 3;
645 : }
646 0 : if (n == 0) {
647 0 : sign = test;
648 0 : continue;
649 : }
650 0 : if (test * sign < 0) {
651 0 : return 1;
652 : }
653 : }
654 0 : return 0;
655 : }
656 :
657 : template<typename TCurve, typename OppCurve>
658 0 : bool SkTSpan<TCurve, OppCurve>::onlyEndPointsInCommon(const SkTSpan<OppCurve, TCurve>* opp,
659 : bool* start, bool* oppStart, bool* ptsInCommon) {
660 0 : if (opp->fPart[0] == fPart[0]) {
661 0 : *start = *oppStart = true;
662 0 : } else if (opp->fPart[0] == fPart[TCurve::kPointLast]) {
663 0 : *start = false;
664 0 : *oppStart = true;
665 0 : } else if (opp->fPart[OppCurve::kPointLast] == fPart[0]) {
666 0 : *start = true;
667 0 : *oppStart = false;
668 0 : } else if (opp->fPart[OppCurve::kPointLast] == fPart[TCurve::kPointLast]) {
669 0 : *start = *oppStart = false;
670 : } else {
671 0 : *ptsInCommon = false;
672 0 : return false;
673 : }
674 0 : *ptsInCommon = true;
675 : const SkDPoint* otherPts[TCurve::kPointCount - 1], * oppOtherPts[OppCurve::kPointCount - 1];
676 0 : int baseIndex = *start ? 0 : TCurve::kPointLast;
677 0 : fPart.otherPts(baseIndex, otherPts);
678 0 : opp->fPart.otherPts(*oppStart ? 0 : OppCurve::kPointLast, oppOtherPts);
679 0 : const SkDPoint& base = fPart[baseIndex];
680 0 : for (int o1 = 0; o1 < (int) SK_ARRAY_COUNT(otherPts); ++o1) {
681 0 : SkDVector v1 = *otherPts[o1] - base;
682 0 : for (int o2 = 0; o2 < (int) SK_ARRAY_COUNT(oppOtherPts); ++o2) {
683 0 : SkDVector v2 = *oppOtherPts[o2] - base;
684 0 : if (v2.dot(v1) >= 0) {
685 0 : return false;
686 : }
687 : }
688 : }
689 0 : return true;
690 : }
691 :
692 : template<typename TCurve, typename OppCurve>
693 0 : SkTSpan<OppCurve, TCurve>* SkTSpan<TCurve, OppCurve>::oppT(double t) const {
694 0 : SkTSpanBounded<OppCurve, TCurve>* bounded = fBounded;
695 0 : while (bounded) {
696 0 : SkTSpan<OppCurve, TCurve>* test = bounded->fBounded;
697 0 : if (between(test->fStartT, t, test->fEndT)) {
698 0 : return test;
699 : }
700 0 : bounded = bounded->fNext;
701 : }
702 0 : return nullptr;
703 : }
704 :
705 : template<typename TCurve, typename OppCurve>
706 0 : bool SkTSpan<TCurve, OppCurve>::removeAllBounded() {
707 0 : bool deleteSpan = false;
708 0 : SkTSpanBounded<OppCurve, TCurve>* bounded = fBounded;
709 0 : while (bounded) {
710 0 : SkTSpan<OppCurve, TCurve>* opp = bounded->fBounded;
711 0 : deleteSpan |= opp->removeBounded(this);
712 0 : bounded = bounded->fNext;
713 : }
714 0 : return deleteSpan;
715 : }
716 :
717 : template<typename TCurve, typename OppCurve>
718 0 : bool SkTSpan<TCurve, OppCurve>::removeBounded(const SkTSpan<OppCurve, TCurve>* opp) {
719 0 : if (fHasPerp) {
720 0 : bool foundStart = false;
721 0 : bool foundEnd = false;
722 0 : SkTSpanBounded<OppCurve, TCurve>* bounded = fBounded;
723 0 : while (bounded) {
724 0 : SkTSpan<OppCurve, TCurve>* test = bounded->fBounded;
725 0 : if (opp != test) {
726 0 : foundStart |= between(test->fStartT, fCoinStart.perpT(), test->fEndT);
727 0 : foundEnd |= between(test->fStartT, fCoinEnd.perpT(), test->fEndT);
728 : }
729 0 : bounded = bounded->fNext;
730 : }
731 0 : if (!foundStart || !foundEnd) {
732 0 : fHasPerp = false;
733 0 : fCoinStart.init();
734 0 : fCoinEnd.init();
735 : }
736 : }
737 0 : SkTSpanBounded<OppCurve, TCurve>* bounded = fBounded;
738 0 : SkTSpanBounded<OppCurve, TCurve>* prev = nullptr;
739 0 : while (bounded) {
740 0 : SkTSpanBounded<OppCurve, TCurve>* boundedNext = bounded->fNext;
741 0 : if (opp == bounded->fBounded) {
742 0 : if (prev) {
743 0 : prev->fNext = boundedNext;
744 0 : return false;
745 : } else {
746 0 : fBounded = boundedNext;
747 0 : return fBounded == nullptr;
748 : }
749 : }
750 0 : prev = bounded;
751 0 : bounded = boundedNext;
752 : }
753 0 : SkOPASSERT(0);
754 0 : return false;
755 : }
756 :
757 : template<typename TCurve, typename OppCurve>
758 0 : bool SkTSpan<TCurve, OppCurve>::splitAt(SkTSpan* work, double t, SkArenaAlloc* heap) {
759 0 : fStartT = t;
760 0 : fEndT = work->fEndT;
761 0 : if (fStartT == fEndT) {
762 0 : fCollapsed = true;
763 0 : return false;
764 : }
765 0 : work->fEndT = t;
766 0 : if (work->fStartT == work->fEndT) {
767 0 : work->fCollapsed = true;
768 0 : return false;
769 : }
770 0 : fPrev = work;
771 0 : fNext = work->fNext;
772 0 : fIsLinear = work->fIsLinear;
773 0 : fIsLine = work->fIsLine;
774 :
775 0 : work->fNext = this;
776 0 : if (fNext) {
777 0 : fNext->fPrev = this;
778 : }
779 0 : this->validate();
780 0 : SkTSpanBounded<OppCurve, TCurve>* bounded = work->fBounded;
781 0 : fBounded = nullptr;
782 0 : while (bounded) {
783 0 : this->addBounded(bounded->fBounded, heap);
784 0 : bounded = bounded->fNext;
785 : }
786 0 : bounded = fBounded;
787 0 : while (bounded) {
788 0 : bounded->fBounded->addBounded(this, heap);
789 0 : bounded = bounded->fNext;
790 : }
791 0 : return true;
792 : }
793 :
794 : template<typename TCurve, typename OppCurve>
795 0 : void SkTSpan<TCurve, OppCurve>::validate() const {
796 : #if DEBUG_VALIDATE
797 : SkASSERT(this != fPrev);
798 : SkASSERT(this != fNext);
799 : SkASSERT(fNext == nullptr || fNext != fPrev);
800 : SkASSERT(fNext == nullptr || this == fNext->fPrev);
801 : SkASSERT(fPrev == nullptr || this == fPrev->fNext);
802 : this->validateBounded();
803 : #endif
804 : #if DEBUG_T_SECT
805 : SkASSERT(fBounds.width() || fBounds.height() || fCollapsed);
806 : SkASSERT(fBoundsMax == SkTMax(fBounds.width(), fBounds.height()) || fCollapsed == 0xFF);
807 : SkASSERT(0 <= fStartT);
808 : SkASSERT(fEndT <= 1);
809 : SkASSERT(fStartT <= fEndT);
810 : SkASSERT(fBounded || fCollapsed == 0xFF);
811 : if (fHasPerp) {
812 : if (fCoinStart.isMatch()) {
813 : validatePerpT(fCoinStart.perpT());
814 : validatePerpPt(fCoinStart.perpT(), fCoinStart.perpPt());
815 : }
816 : if (fCoinEnd.isMatch()) {
817 : validatePerpT(fCoinEnd.perpT());
818 : validatePerpPt(fCoinEnd.perpT(), fCoinEnd.perpPt());
819 : }
820 : }
821 : #endif
822 0 : }
823 :
824 : template<typename TCurve, typename OppCurve>
825 : void SkTSpan<TCurve, OppCurve>::validateBounded() const {
826 : #if DEBUG_VALIDATE
827 : const SkTSpanBounded<OppCurve, TCurve>* testBounded = fBounded;
828 : while (testBounded) {
829 : SkDEBUGCODE(const SkTSpan<OppCurve, TCurve>* overlap = testBounded->fBounded);
830 : SkASSERT(!overlap->fDeleted);
831 : #if DEBUG_T_SECT
832 : SkASSERT(((this->debugID() ^ overlap->debugID()) & 1) == 1);
833 : SkASSERT(overlap->findOppSpan(this));
834 : #endif
835 : testBounded = testBounded->fNext;
836 : }
837 : #endif
838 : }
839 :
840 : template<typename TCurve, typename OppCurve>
841 : void SkTSpan<TCurve, OppCurve>::validatePerpT(double oppT) const {
842 : const SkTSpanBounded<OppCurve, TCurve>* testBounded = fBounded;
843 : while (testBounded) {
844 : const SkTSpan<OppCurve, TCurve>* overlap = testBounded->fBounded;
845 : if (precisely_between(overlap->fStartT, oppT, overlap->fEndT)) {
846 : return;
847 : }
848 : testBounded = testBounded->fNext;
849 : }
850 : SkASSERT(0);
851 : }
852 :
853 : template<typename TCurve, typename OppCurve>
854 : void SkTSpan<TCurve, OppCurve>::validatePerpPt(double t, const SkDPoint& pt) const {
855 : SkASSERT(fDebugSect->fOppSect->fCurve.ptAtT(t) == pt);
856 : }
857 :
858 :
859 : template<typename TCurve, typename OppCurve>
860 0 : SkTSect<TCurve, OppCurve>::SkTSect(const TCurve& c
861 : SkDEBUGPARAMS(SkOpGlobalState* debugGlobalState)
862 : PATH_OPS_DEBUG_T_SECT_PARAMS(int id))
863 : : fCurve(c)
864 : , fHeap(sizeof(SkTSpan<TCurve, OppCurve>) * 4)
865 : , fCoincident(nullptr)
866 : , fDeleted(nullptr)
867 : , fActiveCount(0)
868 0 : SkDEBUGPARAMS(fDebugGlobalState(debugGlobalState))
869 : PATH_OPS_DEBUG_T_SECT_PARAMS(fID(id))
870 : PATH_OPS_DEBUG_T_SECT_PARAMS(fDebugCount(0))
871 : PATH_OPS_DEBUG_T_SECT_PARAMS(fDebugAllocatedCount(0))
872 : {
873 0 : this->resetRemovedEnds();
874 0 : fHead = this->addOne();
875 0 : SkDEBUGCODE(fHead->debugSetGlobalState(debugGlobalState));
876 0 : fHead->init(c);
877 0 : }
878 :
879 : template<typename TCurve, typename OppCurve>
880 0 : SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::addOne() {
881 : SkTSpan<TCurve, OppCurve>* result;
882 0 : if (fDeleted) {
883 0 : result = fDeleted;
884 0 : fDeleted = result->fNext;
885 : } else {
886 0 : result = fHeap.make<SkTSpan<TCurve, OppCurve>>();
887 : #if DEBUG_T_SECT
888 : ++fDebugAllocatedCount;
889 : #endif
890 : }
891 0 : result->reset();
892 0 : result->fHasPerp = false;
893 0 : result->fDeleted = false;
894 0 : ++fActiveCount;
895 : PATH_OPS_DEBUG_T_SECT_CODE(result->fID = fDebugCount++ * 2 + fID);
896 0 : SkDEBUGCODE(result->fDebugSect = this);
897 : #ifdef SK_DEBUG
898 0 : result->fPart.debugInit();
899 0 : result->fCoinStart.debugInit();
900 0 : result->fCoinEnd.debugInit();
901 0 : result->fPrev = result->fNext = nullptr;
902 0 : result->fBounds.debugInit();
903 0 : result->fStartT = result->fEndT = result->fBoundsMax = SK_ScalarNaN;
904 0 : result->fCollapsed = result->fIsLinear = result->fIsLine = 0xFF;
905 : #endif
906 0 : return result;
907 : }
908 :
909 : template<typename TCurve, typename OppCurve>
910 0 : bool SkTSect<TCurve, OppCurve>::binarySearchCoin(SkTSect<OppCurve, TCurve>* sect2, double tStart,
911 : double tStep, double* resultT, double* oppT) {
912 0 : SkTSpan<TCurve, OppCurve> work;
913 0 : double result = work.fStartT = work.fEndT = tStart;
914 0 : SkDEBUGCODE(work.fDebugSect = this);
915 0 : SkDPoint last = fCurve.ptAtT(tStart);
916 : SkDPoint oppPt;
917 0 : bool flip = false;
918 0 : bool contained = false;
919 0 : SkDEBUGCODE(bool down = tStep < 0);
920 0 : const OppCurve& opp = sect2->fCurve;
921 : do {
922 0 : tStep *= 0.5;
923 0 : work.fStartT += tStep;
924 0 : if (flip) {
925 0 : tStep = -tStep;
926 0 : flip = false;
927 : }
928 0 : work.initBounds(fCurve);
929 0 : if (work.fCollapsed) {
930 0 : return false;
931 : }
932 0 : if (last.approximatelyEqual(work.fPart[0])) {
933 0 : break;
934 : }
935 0 : last = work.fPart[0];
936 0 : work.fCoinStart.setPerp(fCurve, work.fStartT, last, opp);
937 0 : if (work.fCoinStart.isMatch()) {
938 : #if DEBUG_T_SECT
939 : work.validatePerpPt(work.fCoinStart.perpT(), work.fCoinStart.perpPt());
940 : #endif
941 0 : double oppTTest = work.fCoinStart.perpT();
942 0 : if (sect2->fHead->contains(oppTTest)) {
943 0 : *oppT = oppTTest;
944 0 : oppPt = work.fCoinStart.perpPt();
945 0 : contained = true;
946 0 : SkASSERT(down ? result > work.fStartT : result < work.fStartT);
947 0 : result = work.fStartT;
948 0 : continue;
949 : }
950 : }
951 0 : tStep = -tStep;
952 0 : flip = true;
953 : } while (true);
954 0 : if (!contained) {
955 0 : return false;
956 : }
957 0 : if (last.approximatelyEqual(fCurve[0])) {
958 0 : result = 0;
959 0 : } else if (last.approximatelyEqual(fCurve[TCurve::kPointLast])) {
960 0 : result = 1;
961 : }
962 0 : if (oppPt.approximatelyEqual(opp[0])) {
963 0 : *oppT = 0;
964 0 : } else if (oppPt.approximatelyEqual(opp[OppCurve::kPointLast])) {
965 0 : *oppT = 1;
966 : }
967 0 : *resultT = result;
968 0 : return true;
969 : }
970 :
971 : // OPTIMIZE ? keep a sorted list of sizes in the form of a doubly-linked list in quad span
972 : // so that each quad sect has a pointer to the largest, and can update it as spans
973 : // are split
974 : template<typename TCurve, typename OppCurve>
975 0 : SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::boundsMax() const {
976 0 : SkTSpan<TCurve, OppCurve>* test = fHead;
977 0 : SkTSpan<TCurve, OppCurve>* largest = fHead;
978 0 : bool lCollapsed = largest->fCollapsed;
979 0 : while ((test = test->fNext)) {
980 0 : bool tCollapsed = test->fCollapsed;
981 0 : if ((lCollapsed && !tCollapsed) || (lCollapsed == tCollapsed &&
982 0 : largest->fBoundsMax < test->fBoundsMax)) {
983 0 : largest = test;
984 0 : lCollapsed = test->fCollapsed;
985 : }
986 : }
987 0 : return largest;
988 : }
989 :
990 : template<typename TCurve, typename OppCurve>
991 0 : bool SkTSect<TCurve, OppCurve>::coincidentCheck(SkTSect<OppCurve, TCurve>* sect2) {
992 0 : SkTSpan<TCurve, OppCurve>* first = fHead;
993 0 : if (!first) {
994 0 : return false;
995 : }
996 : SkTSpan<TCurve, OppCurve>* last, * next;
997 0 : do {
998 0 : int consecutive = this->countConsecutiveSpans(first, &last);
999 0 : next = last->fNext;
1000 0 : if (consecutive < COINCIDENT_SPAN_COUNT) {
1001 0 : continue;
1002 : }
1003 0 : this->validate();
1004 0 : sect2->validate();
1005 0 : this->computePerpendiculars(sect2, first, last);
1006 0 : this->validate();
1007 0 : sect2->validate();
1008 : // check to see if a range of points are on the curve
1009 0 : SkTSpan<TCurve, OppCurve>* coinStart = first;
1010 0 : do {
1011 0 : bool success = this->extractCoincident(sect2, coinStart, last, &coinStart);
1012 0 : if (!success) {
1013 0 : return false;
1014 : }
1015 0 : } while (coinStart && !last->fDeleted);
1016 0 : if (!fHead || !sect2->fHead) {
1017 : break;
1018 : }
1019 0 : if (!next || next->fDeleted) {
1020 : break;
1021 : }
1022 : } while ((first = next));
1023 0 : return true;
1024 : }
1025 :
1026 : template<typename TCurve, typename OppCurve>
1027 0 : void SkTSect<TCurve, OppCurve>::coincidentForce(SkTSect<OppCurve, TCurve>* sect2,
1028 : double start1s, double start1e) {
1029 0 : SkTSpan<TCurve, OppCurve>* first = fHead;
1030 0 : SkTSpan<TCurve, OppCurve>* last = this->tail();
1031 0 : SkTSpan<OppCurve, TCurve>* oppFirst = sect2->fHead;
1032 0 : SkTSpan<OppCurve, TCurve>* oppLast = sect2->tail();
1033 0 : bool deleteEmptySpans = this->updateBounded(first, last, oppFirst);
1034 0 : deleteEmptySpans |= sect2->updateBounded(oppFirst, oppLast, first);
1035 0 : this->removeSpanRange(first, last);
1036 0 : sect2->removeSpanRange(oppFirst, oppLast);
1037 0 : first->fStartT = start1s;
1038 0 : first->fEndT = start1e;
1039 0 : first->resetBounds(fCurve);
1040 0 : first->fCoinStart.setPerp(fCurve, start1s, fCurve[0], sect2->fCurve);
1041 0 : first->fCoinEnd.setPerp(fCurve, start1e, fCurve[TCurve::kPointLast], sect2->fCurve);
1042 0 : bool oppMatched = first->fCoinStart.perpT() < first->fCoinEnd.perpT();
1043 0 : double oppStartT = first->fCoinStart.perpT() == -1 ? 0 : SkTMax(0., first->fCoinStart.perpT());
1044 0 : double oppEndT = first->fCoinEnd.perpT() == -1 ? 1 : SkTMin(1., first->fCoinEnd.perpT());
1045 0 : if (!oppMatched) {
1046 0 : SkTSwap(oppStartT, oppEndT);
1047 : }
1048 0 : oppFirst->fStartT = oppStartT;
1049 0 : oppFirst->fEndT = oppEndT;
1050 0 : oppFirst->resetBounds(sect2->fCurve);
1051 0 : this->removeCoincident(first, false);
1052 0 : sect2->removeCoincident(oppFirst, true);
1053 0 : if (deleteEmptySpans) {
1054 0 : this->deleteEmptySpans();
1055 0 : sect2->deleteEmptySpans();
1056 : }
1057 0 : }
1058 :
1059 : template<typename TCurve, typename OppCurve>
1060 0 : bool SkTSect<TCurve, OppCurve>::coincidentHasT(double t) {
1061 0 : SkTSpan<TCurve, OppCurve>* test = fCoincident;
1062 0 : while (test) {
1063 0 : if (between(test->fStartT, t, test->fEndT)) {
1064 0 : return true;
1065 : }
1066 0 : test = test->fNext;
1067 : }
1068 0 : return false;
1069 : }
1070 :
1071 : template<typename TCurve, typename OppCurve>
1072 0 : int SkTSect<TCurve, OppCurve>::collapsed() const {
1073 0 : int result = 0;
1074 0 : const SkTSpan<TCurve, OppCurve>* test = fHead;
1075 0 : while (test) {
1076 0 : if (test->fCollapsed) {
1077 0 : ++result;
1078 : }
1079 0 : test = test->next();
1080 : }
1081 0 : return result;
1082 : }
1083 :
1084 : template<typename TCurve, typename OppCurve>
1085 0 : void SkTSect<TCurve, OppCurve>::computePerpendiculars(SkTSect<OppCurve, TCurve>* sect2,
1086 : SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>* last) {
1087 0 : const OppCurve& opp = sect2->fCurve;
1088 0 : SkTSpan<TCurve, OppCurve>* work = first;
1089 0 : SkTSpan<TCurve, OppCurve>* prior = nullptr;
1090 : do {
1091 0 : if (!work->fHasPerp && !work->fCollapsed) {
1092 0 : if (prior) {
1093 0 : work->fCoinStart = prior->fCoinEnd;
1094 : } else {
1095 0 : work->fCoinStart.setPerp(fCurve, work->fStartT, work->fPart[0], opp);
1096 : }
1097 0 : if (work->fCoinStart.isMatch()) {
1098 0 : double perpT = work->fCoinStart.perpT();
1099 0 : if (sect2->coincidentHasT(perpT)) {
1100 0 : work->fCoinStart.init();
1101 : } else {
1102 0 : sect2->addForPerp(work, perpT);
1103 : }
1104 : }
1105 0 : work->fCoinEnd.setPerp(fCurve, work->fEndT, work->fPart[TCurve::kPointLast], opp);
1106 0 : if (work->fCoinEnd.isMatch()) {
1107 0 : double perpT = work->fCoinEnd.perpT();
1108 0 : if (sect2->coincidentHasT(perpT)) {
1109 0 : work->fCoinEnd.init();
1110 : } else {
1111 0 : sect2->addForPerp(work, perpT);
1112 : }
1113 : }
1114 0 : work->fHasPerp = true;
1115 : }
1116 0 : if (work == last) {
1117 0 : break;
1118 : }
1119 0 : prior = work;
1120 0 : work = work->fNext;
1121 0 : SkASSERT(work);
1122 : } while (true);
1123 0 : }
1124 :
1125 : template<typename TCurve, typename OppCurve>
1126 0 : int SkTSect<TCurve, OppCurve>::countConsecutiveSpans(SkTSpan<TCurve, OppCurve>* first,
1127 : SkTSpan<TCurve, OppCurve>** lastPtr) const {
1128 0 : int consecutive = 1;
1129 0 : SkTSpan<TCurve, OppCurve>* last = first;
1130 : do {
1131 0 : SkTSpan<TCurve, OppCurve>* next = last->fNext;
1132 0 : if (!next) {
1133 0 : break;
1134 : }
1135 0 : if (next->fStartT > last->fEndT) {
1136 0 : break;
1137 : }
1138 0 : ++consecutive;
1139 0 : last = next;
1140 : } while (true);
1141 0 : *lastPtr = last;
1142 0 : return consecutive;
1143 : }
1144 :
1145 : template<typename TCurve, typename OppCurve>
1146 0 : bool SkTSect<TCurve, OppCurve>::debugHasBounded(const SkTSpan<OppCurve, TCurve>* span) const {
1147 0 : const SkTSpan<TCurve, OppCurve>* test = fHead;
1148 0 : if (!test) {
1149 0 : return false;
1150 : }
1151 0 : do {
1152 0 : if (test->findOppSpan(span)) {
1153 0 : return true;
1154 : }
1155 : } while ((test = test->next()));
1156 0 : return false;
1157 : }
1158 :
1159 : template<typename TCurve, typename OppCurve>
1160 0 : bool SkTSect<TCurve, OppCurve>::deleteEmptySpans() {
1161 : SkTSpan<TCurve, OppCurve>* test;
1162 0 : SkTSpan<TCurve, OppCurve>* next = fHead;
1163 0 : int safetyHatch = 1000;
1164 0 : while ((test = next)) {
1165 0 : next = test->fNext;
1166 0 : if (!test->fBounded) {
1167 0 : if (!this->removeSpan(test)) {
1168 0 : return false;
1169 : }
1170 : }
1171 0 : if (--safetyHatch < 0) {
1172 0 : return false;
1173 : }
1174 : }
1175 0 : return true;
1176 : }
1177 :
1178 : template<typename TCurve, typename OppCurve>
1179 0 : bool SkTSect<TCurve, OppCurve>::extractCoincident(
1180 : SkTSect<OppCurve, TCurve>* sect2,
1181 : SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>* last,
1182 : SkTSpan<TCurve, OppCurve>** result) {
1183 0 : first = findCoincidentRun(first, &last);
1184 0 : if (!first || !last) {
1185 0 : *result = nullptr;
1186 0 : return true;
1187 : }
1188 : // march outwards to find limit of coincidence from here to previous and next spans
1189 0 : double startT = first->fStartT;
1190 0 : double oppStartT SK_INIT_TO_AVOID_WARNING;
1191 0 : double oppEndT SK_INIT_TO_AVOID_WARNING;
1192 0 : SkTSpan<TCurve, OppCurve>* prev = first->fPrev;
1193 0 : SkASSERT(first->fCoinStart.isMatch());
1194 0 : SkTSpan<OppCurve, TCurve>* oppFirst = first->findOppT(first->fCoinStart.perpT());
1195 0 : SkOPASSERT(last->fCoinEnd.isMatch());
1196 0 : bool oppMatched = first->fCoinStart.perpT() < first->fCoinEnd.perpT();
1197 : double coinStart;
1198 : SkDEBUGCODE(double coinEnd);
1199 : SkTSpan<OppCurve, TCurve>* cutFirst;
1200 0 : if (prev && prev->fEndT == startT
1201 0 : && this->binarySearchCoin(sect2, startT, prev->fStartT - startT, &coinStart,
1202 : &oppStartT)
1203 0 : && prev->fStartT < coinStart && coinStart < startT
1204 0 : && (cutFirst = prev->oppT(oppStartT))) {
1205 0 : oppFirst = cutFirst;
1206 0 : first = this->addSplitAt(prev, coinStart);
1207 0 : first->markCoincident();
1208 0 : prev->fCoinEnd.markCoincident();
1209 0 : if (oppFirst->fStartT < oppStartT && oppStartT < oppFirst->fEndT) {
1210 0 : SkTSpan<OppCurve, TCurve>* oppHalf = sect2->addSplitAt(oppFirst, oppStartT);
1211 0 : if (oppMatched) {
1212 0 : oppFirst->fCoinEnd.markCoincident();
1213 0 : oppHalf->markCoincident();
1214 0 : oppFirst = oppHalf;
1215 : } else {
1216 0 : oppFirst->markCoincident();
1217 0 : oppHalf->fCoinStart.markCoincident();
1218 : }
1219 : }
1220 : } else {
1221 0 : SkDEBUGCODE(coinStart = first->fStartT);
1222 0 : FAIL_IF(!oppFirst);
1223 0 : SkDEBUGCODE(oppStartT = oppMatched ? oppFirst->fStartT : oppFirst->fEndT);
1224 : }
1225 : // FIXME: incomplete : if we're not at the end, find end of coin
1226 : SkTSpan<OppCurve, TCurve>* oppLast;
1227 0 : SkOPASSERT(last->fCoinEnd.isMatch());
1228 0 : oppLast = last->findOppT(last->fCoinEnd.perpT());
1229 0 : SkDEBUGCODE(coinEnd = last->fEndT);
1230 : #ifdef SK_DEBUG
1231 0 : if (!this->globalState() || !this->globalState()->debugSkipAssert()) {
1232 0 : oppEndT = oppMatched ? oppLast->fEndT : oppLast->fStartT;
1233 : }
1234 : #endif
1235 0 : if (!oppMatched) {
1236 0 : SkTSwap(oppFirst, oppLast);
1237 0 : SkTSwap(oppStartT, oppEndT);
1238 : }
1239 0 : SkOPASSERT(oppStartT < oppEndT);
1240 0 : SkASSERT(coinStart == first->fStartT);
1241 0 : SkASSERT(coinEnd == last->fEndT);
1242 0 : SkOPASSERT(oppStartT == oppFirst->fStartT);
1243 0 : SkOPASSERT(oppEndT == oppLast->fEndT);
1244 0 : if (!oppFirst) {
1245 0 : *result = nullptr;
1246 0 : return true;
1247 : }
1248 0 : if (!oppLast) {
1249 0 : *result = nullptr;
1250 0 : return true;
1251 : }
1252 : // reduce coincident runs to single entries
1253 0 : this->validate();
1254 0 : sect2->validate();
1255 0 : bool deleteEmptySpans = this->updateBounded(first, last, oppFirst);
1256 0 : deleteEmptySpans |= sect2->updateBounded(oppFirst, oppLast, first);
1257 0 : this->removeSpanRange(first, last);
1258 0 : sect2->removeSpanRange(oppFirst, oppLast);
1259 0 : first->fEndT = last->fEndT;
1260 0 : first->resetBounds(this->fCurve);
1261 0 : first->fCoinStart.setPerp(fCurve, first->fStartT, first->fPart[0], sect2->fCurve);
1262 0 : first->fCoinEnd.setPerp(fCurve, first->fEndT, first->fPart[TCurve::kPointLast], sect2->fCurve);
1263 0 : oppStartT = first->fCoinStart.perpT();
1264 0 : oppEndT = first->fCoinEnd.perpT();
1265 0 : if (between(0, oppStartT, 1) && between(0, oppEndT, 1)) {
1266 0 : if (!oppMatched) {
1267 0 : SkTSwap(oppStartT, oppEndT);
1268 : }
1269 0 : oppFirst->fStartT = oppStartT;
1270 0 : oppFirst->fEndT = oppEndT;
1271 0 : oppFirst->resetBounds(sect2->fCurve);
1272 : }
1273 0 : this->validateBounded();
1274 0 : sect2->validateBounded();
1275 0 : last = first->fNext;
1276 0 : this->removeCoincident(first, false);
1277 0 : sect2->removeCoincident(oppFirst, true);
1278 0 : if (deleteEmptySpans) {
1279 0 : if (!this->deleteEmptySpans() || !sect2->deleteEmptySpans()) {
1280 0 : *result = nullptr;
1281 0 : return false;
1282 : }
1283 : }
1284 0 : this->validate();
1285 0 : sect2->validate();
1286 0 : *result = last && !last->fDeleted && fHead && sect2->fHead ? last : nullptr;
1287 0 : return true;
1288 : }
1289 :
1290 : template<typename TCurve, typename OppCurve>
1291 0 : SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::findCoincidentRun(
1292 : SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>** lastPtr) {
1293 0 : SkTSpan<TCurve, OppCurve>* work = first;
1294 0 : SkTSpan<TCurve, OppCurve>* lastCandidate = nullptr;
1295 0 : first = nullptr;
1296 : // find the first fully coincident span
1297 : do {
1298 0 : if (work->fCoinStart.isMatch()) {
1299 : #if DEBUG_T_SECT
1300 : work->validatePerpT(work->fCoinStart.perpT());
1301 : work->validatePerpPt(work->fCoinStart.perpT(), work->fCoinStart.perpPt());
1302 : #endif
1303 0 : SkOPASSERT(work->hasOppT(work->fCoinStart.perpT()));
1304 0 : if (!work->fCoinEnd.isMatch()) {
1305 0 : break;
1306 : }
1307 0 : lastCandidate = work;
1308 0 : if (!first) {
1309 0 : first = work;
1310 : }
1311 0 : } else if (first && work->fCollapsed) {
1312 0 : *lastPtr = lastCandidate;
1313 0 : return first;
1314 : } else {
1315 0 : lastCandidate = nullptr;
1316 0 : SkOPASSERT(!first);
1317 : }
1318 0 : if (work == *lastPtr) {
1319 0 : return first;
1320 : }
1321 0 : work = work->fNext;
1322 0 : if (!work) {
1323 0 : return nullptr;
1324 : }
1325 : } while (true);
1326 0 : if (lastCandidate) {
1327 0 : *lastPtr = lastCandidate;
1328 : }
1329 0 : return first;
1330 : }
1331 :
1332 : template<typename TCurve, typename OppCurve>
1333 0 : int SkTSect<TCurve, OppCurve>::intersects(SkTSpan<TCurve, OppCurve>* span,
1334 : SkTSect<OppCurve, TCurve>* opp,
1335 : SkTSpan<OppCurve, TCurve>* oppSpan, int* oppResult) {
1336 : bool spanStart, oppStart;
1337 0 : int hullResult = span->hullsIntersect(oppSpan, &spanStart, &oppStart);
1338 0 : if (hullResult >= 0) {
1339 0 : if (hullResult == 2) { // hulls have one point in common
1340 0 : if (!span->fBounded || !span->fBounded->fNext) {
1341 0 : SkASSERT(!span->fBounded || span->fBounded->fBounded == oppSpan);
1342 0 : if (spanStart) {
1343 0 : span->fEndT = span->fStartT;
1344 : } else {
1345 0 : span->fStartT = span->fEndT;
1346 : }
1347 : } else {
1348 0 : hullResult = 1;
1349 : }
1350 0 : if (!oppSpan->fBounded || !oppSpan->fBounded->fNext) {
1351 0 : SkASSERT(!oppSpan->fBounded || oppSpan->fBounded->fBounded == span);
1352 0 : if (oppStart) {
1353 0 : oppSpan->fEndT = oppSpan->fStartT;
1354 : } else {
1355 0 : oppSpan->fStartT = oppSpan->fEndT;
1356 : }
1357 0 : *oppResult = 2;
1358 : } else {
1359 0 : *oppResult = 1;
1360 : }
1361 : } else {
1362 0 : *oppResult = 1;
1363 : }
1364 0 : return hullResult;
1365 : }
1366 0 : if (span->fIsLine && oppSpan->fIsLine) {
1367 0 : SkIntersections i;
1368 0 : int sects = this->linesIntersect(span, opp, oppSpan, &i);
1369 0 : if (sects == 2) {
1370 0 : return *oppResult = 1;
1371 : }
1372 0 : if (!sects) {
1373 0 : return -1;
1374 : }
1375 0 : this->removedEndCheck(span);
1376 0 : span->fStartT = span->fEndT = i[0][0];
1377 0 : opp->removedEndCheck(oppSpan);
1378 0 : oppSpan->fStartT = oppSpan->fEndT = i[1][0];
1379 0 : return *oppResult = 2;
1380 : }
1381 0 : if (span->fIsLinear || oppSpan->fIsLinear) {
1382 0 : return *oppResult = (int) span->linearsIntersect(oppSpan);
1383 : }
1384 0 : return *oppResult = 1;
1385 : }
1386 :
1387 : template<typename TCurve>
1388 0 : static bool is_parallel(const SkDLine& thisLine, const TCurve& opp) {
1389 0 : if (!opp.IsConic()) {
1390 0 : return false; // FIXME : breaks a lot of stuff now
1391 : }
1392 0 : int finds = 0;
1393 : SkDLine thisPerp;
1394 0 : thisPerp.fPts[0].fX = thisLine.fPts[1].fX + (thisLine.fPts[1].fY - thisLine.fPts[0].fY);
1395 0 : thisPerp.fPts[0].fY = thisLine.fPts[1].fY + (thisLine.fPts[0].fX - thisLine.fPts[1].fX);
1396 0 : thisPerp.fPts[1] = thisLine.fPts[1];
1397 0 : SkIntersections perpRayI;
1398 0 : perpRayI.intersectRay(opp, thisPerp);
1399 0 : for (int pIndex = 0; pIndex < perpRayI.used(); ++pIndex) {
1400 0 : finds += perpRayI.pt(pIndex).approximatelyEqual(thisPerp.fPts[1]);
1401 : }
1402 0 : thisPerp.fPts[1].fX = thisLine.fPts[0].fX + (thisLine.fPts[1].fY - thisLine.fPts[0].fY);
1403 0 : thisPerp.fPts[1].fY = thisLine.fPts[0].fY + (thisLine.fPts[0].fX - thisLine.fPts[1].fX);
1404 0 : thisPerp.fPts[0] = thisLine.fPts[0];
1405 0 : perpRayI.intersectRay(opp, thisPerp);
1406 0 : for (int pIndex = 0; pIndex < perpRayI.used(); ++pIndex) {
1407 0 : finds += perpRayI.pt(pIndex).approximatelyEqual(thisPerp.fPts[0]);
1408 : }
1409 0 : return finds >= 2;
1410 : }
1411 :
1412 : // while the intersection points are sufficiently far apart:
1413 : // construct the tangent lines from the intersections
1414 : // find the point where the tangent line intersects the opposite curve
1415 : template<typename TCurve, typename OppCurve>
1416 0 : int SkTSect<TCurve, OppCurve>::linesIntersect(SkTSpan<TCurve, OppCurve>* span,
1417 : SkTSect<OppCurve, TCurve>* opp,
1418 : SkTSpan<OppCurve, TCurve>* oppSpan, SkIntersections* i) {
1419 0 : SkIntersections thisRayI SkDEBUGCODE((span->fDebugGlobalState));
1420 0 : SkIntersections oppRayI SkDEBUGCODE((span->fDebugGlobalState));
1421 0 : SkDLine thisLine = {{ span->fPart[0], span->fPart[TCurve::kPointLast] }};
1422 0 : SkDLine oppLine = {{ oppSpan->fPart[0], oppSpan->fPart[OppCurve::kPointLast] }};
1423 0 : int loopCount = 0;
1424 0 : double bestDistSq = DBL_MAX;
1425 0 : if (!thisRayI.intersectRay(opp->fCurve, thisLine)) {
1426 0 : return 0;
1427 : }
1428 0 : if (!oppRayI.intersectRay(this->fCurve, oppLine)) {
1429 0 : return 0;
1430 : }
1431 : // if the ends of each line intersect the opposite curve, the lines are coincident
1432 0 : if (thisRayI.used() > 1) {
1433 0 : int ptMatches = 0;
1434 0 : for (int tIndex = 0; tIndex < thisRayI.used(); ++tIndex) {
1435 0 : for (int lIndex = 0; lIndex < (int) SK_ARRAY_COUNT(thisLine.fPts); ++lIndex) {
1436 0 : ptMatches += thisRayI.pt(tIndex).approximatelyEqual(thisLine.fPts[lIndex]);
1437 : }
1438 : }
1439 0 : if (ptMatches == 2 || is_parallel(thisLine, opp->fCurve)) {
1440 0 : return 2;
1441 : }
1442 : }
1443 0 : if (oppRayI.used() > 1) {
1444 0 : int ptMatches = 0;
1445 0 : for (int oIndex = 0; oIndex < oppRayI.used(); ++oIndex) {
1446 0 : for (int lIndex = 0; lIndex < (int) SK_ARRAY_COUNT(thisLine.fPts); ++lIndex) {
1447 0 : ptMatches += oppRayI.pt(oIndex).approximatelyEqual(oppLine.fPts[lIndex]);
1448 : }
1449 : }
1450 0 : if (ptMatches == 2|| is_parallel(oppLine, this->fCurve)) {
1451 0 : return 2;
1452 : }
1453 : }
1454 : do {
1455 : // pick the closest pair of points
1456 0 : double closest = DBL_MAX;
1457 0 : int closeIndex SK_INIT_TO_AVOID_WARNING;
1458 0 : int oppCloseIndex SK_INIT_TO_AVOID_WARNING;
1459 0 : for (int index = 0; index < oppRayI.used(); ++index) {
1460 0 : if (!roughly_between(span->fStartT, oppRayI[0][index], span->fEndT)) {
1461 0 : continue;
1462 : }
1463 0 : for (int oIndex = 0; oIndex < thisRayI.used(); ++oIndex) {
1464 0 : if (!roughly_between(oppSpan->fStartT, thisRayI[0][oIndex], oppSpan->fEndT)) {
1465 0 : continue;
1466 : }
1467 0 : double distSq = thisRayI.pt(index).distanceSquared(oppRayI.pt(oIndex));
1468 0 : if (closest > distSq) {
1469 0 : closest = distSq;
1470 0 : closeIndex = index;
1471 0 : oppCloseIndex = oIndex;
1472 : }
1473 : }
1474 : }
1475 0 : if (closest == DBL_MAX) {
1476 0 : break;
1477 : }
1478 0 : const SkDPoint& oppIPt = thisRayI.pt(oppCloseIndex);
1479 0 : const SkDPoint& iPt = oppRayI.pt(closeIndex);
1480 0 : if (between(span->fStartT, oppRayI[0][closeIndex], span->fEndT)
1481 0 : && between(oppSpan->fStartT, thisRayI[0][oppCloseIndex], oppSpan->fEndT)
1482 0 : && oppIPt.approximatelyEqual(iPt)) {
1483 0 : i->merge(oppRayI, closeIndex, thisRayI, oppCloseIndex);
1484 0 : return i->used();
1485 : }
1486 0 : double distSq = oppIPt.distanceSquared(iPt);
1487 0 : if (bestDistSq < distSq || ++loopCount > 5) {
1488 0 : return 0;
1489 : }
1490 0 : bestDistSq = distSq;
1491 0 : double oppStart = oppRayI[0][closeIndex];
1492 0 : thisLine[0] = fCurve.ptAtT(oppStart);
1493 0 : thisLine[1] = thisLine[0] + fCurve.dxdyAtT(oppStart);
1494 0 : if (!thisRayI.intersectRay(opp->fCurve, thisLine)) {
1495 0 : break;
1496 : }
1497 0 : double start = thisRayI[0][oppCloseIndex];
1498 0 : oppLine[0] = opp->fCurve.ptAtT(start);
1499 0 : oppLine[1] = oppLine[0] + opp->fCurve.dxdyAtT(start);
1500 0 : if (!oppRayI.intersectRay(this->fCurve, oppLine)) {
1501 0 : break;
1502 0 : }
1503 : } while (true);
1504 : // convergence may fail if the curves are nearly coincident
1505 0 : SkTCoincident<OppCurve, TCurve> oCoinS, oCoinE;
1506 0 : oCoinS.setPerp(opp->fCurve, oppSpan->fStartT, oppSpan->fPart[0], fCurve);
1507 0 : oCoinE.setPerp(opp->fCurve, oppSpan->fEndT, oppSpan->fPart[OppCurve::kPointLast], fCurve);
1508 0 : double tStart = oCoinS.perpT();
1509 0 : double tEnd = oCoinE.perpT();
1510 0 : bool swap = tStart > tEnd;
1511 0 : if (swap) {
1512 0 : SkTSwap(tStart, tEnd);
1513 : }
1514 0 : tStart = SkTMax(tStart, span->fStartT);
1515 0 : tEnd = SkTMin(tEnd, span->fEndT);
1516 0 : if (tStart > tEnd) {
1517 0 : return 0;
1518 : }
1519 : SkDVector perpS, perpE;
1520 0 : if (tStart == span->fStartT) {
1521 0 : SkTCoincident<TCurve, OppCurve> coinS;
1522 0 : coinS.setPerp(fCurve, span->fStartT, span->fPart[0], opp->fCurve);
1523 0 : perpS = span->fPart[0] - coinS.perpPt();
1524 0 : } else if (swap) {
1525 0 : perpS = oCoinE.perpPt() - oppSpan->fPart[OppCurve::kPointLast];
1526 : } else {
1527 0 : perpS = oCoinS.perpPt() - oppSpan->fPart[0];
1528 : }
1529 0 : if (tEnd == span->fEndT) {
1530 0 : SkTCoincident<TCurve, OppCurve> coinE;
1531 0 : coinE.setPerp(fCurve, span->fEndT, span->fPart[TCurve::kPointLast], opp->fCurve);
1532 0 : perpE = span->fPart[TCurve::kPointLast] - coinE.perpPt();
1533 0 : } else if (swap) {
1534 0 : perpE = oCoinS.perpPt() - oppSpan->fPart[0];
1535 : } else {
1536 0 : perpE = oCoinE.perpPt() - oppSpan->fPart[OppCurve::kPointLast];
1537 : }
1538 0 : if (perpS.dot(perpE) >= 0) {
1539 0 : return 0;
1540 : }
1541 0 : SkTCoincident<TCurve, OppCurve> coinW;
1542 0 : double workT = tStart;
1543 0 : double tStep = tEnd - tStart;
1544 : SkDPoint workPt;
1545 : do {
1546 0 : tStep *= 0.5;
1547 0 : if (precisely_zero(tStep)) {
1548 0 : return 0;
1549 : }
1550 0 : workT += tStep;
1551 0 : workPt = fCurve.ptAtT(workT);
1552 0 : coinW.setPerp(fCurve, workT, workPt, opp->fCurve);
1553 0 : double perpT = coinW.perpT();
1554 0 : if (coinW.isMatch() ? !between(oppSpan->fStartT, perpT, oppSpan->fEndT) : perpT < 0) {
1555 0 : continue;
1556 : }
1557 0 : SkDVector perpW = workPt - coinW.perpPt();
1558 0 : if ((perpS.dot(perpW) >= 0) == (tStep < 0)) {
1559 0 : tStep = -tStep;
1560 : }
1561 0 : if (workPt.approximatelyEqual(coinW.perpPt())) {
1562 0 : break;
1563 0 : }
1564 : } while (true);
1565 0 : double oppTTest = coinW.perpT();
1566 0 : if (!opp->fHead->contains(oppTTest)) {
1567 0 : return 0;
1568 : }
1569 0 : i->setMax(1);
1570 0 : i->insert(workT, oppTTest, workPt);
1571 0 : return 1;
1572 : }
1573 :
1574 :
1575 : template<typename TCurve, typename OppCurve>
1576 0 : bool SkTSect<TCurve, OppCurve>::markSpanGone(SkTSpan<TCurve, OppCurve>* span) {
1577 0 : if (--fActiveCount < 0) {
1578 0 : return false;
1579 : }
1580 0 : span->fNext = fDeleted;
1581 0 : fDeleted = span;
1582 0 : SkOPASSERT(!span->fDeleted);
1583 0 : span->fDeleted = true;
1584 0 : return true;
1585 : }
1586 :
1587 : template<typename TCurve, typename OppCurve>
1588 : bool SkTSect<TCurve, OppCurve>::matchedDirection(double t, const SkTSect<OppCurve, TCurve>* sect2,
1589 : double t2) const {
1590 : SkDVector dxdy = this->fCurve.dxdyAtT(t);
1591 : SkDVector dxdy2 = sect2->fCurve.dxdyAtT(t2);
1592 : return dxdy.dot(dxdy2) >= 0;
1593 : }
1594 :
1595 : template<typename TCurve, typename OppCurve>
1596 : void SkTSect<TCurve, OppCurve>::matchedDirCheck(double t, const SkTSect<OppCurve, TCurve>* sect2,
1597 : double t2, bool* calcMatched, bool* oppMatched) const {
1598 : if (*calcMatched) {
1599 : SkASSERT(*oppMatched == this->matchedDirection(t, sect2, t2));
1600 : } else {
1601 : *oppMatched = this->matchedDirection(t, sect2, t2);
1602 : *calcMatched = true;
1603 : }
1604 : }
1605 :
1606 : template<typename TCurve, typename OppCurve>
1607 0 : void SkTSect<TCurve, OppCurve>::mergeCoincidence(SkTSect<OppCurve, TCurve>* sect2) {
1608 0 : double smallLimit = 0;
1609 : do {
1610 : // find the smallest unprocessed span
1611 0 : SkTSpan<TCurve, OppCurve>* smaller = nullptr;
1612 0 : SkTSpan<TCurve, OppCurve>* test = fCoincident;
1613 0 : do {
1614 0 : if (!test) {
1615 0 : return;
1616 : }
1617 0 : if (test->fStartT < smallLimit) {
1618 0 : continue;
1619 : }
1620 0 : if (smaller && smaller->fEndT < test->fStartT) {
1621 0 : continue;
1622 : }
1623 0 : smaller = test;
1624 : } while ((test = test->fNext));
1625 0 : if (!smaller) {
1626 0 : return;
1627 : }
1628 0 : smallLimit = smaller->fEndT;
1629 : // find next larger span
1630 0 : SkTSpan<TCurve, OppCurve>* prior = nullptr;
1631 0 : SkTSpan<TCurve, OppCurve>* larger = nullptr;
1632 0 : SkTSpan<TCurve, OppCurve>* largerPrior = nullptr;
1633 0 : test = fCoincident;
1634 0 : do {
1635 0 : if (test->fStartT < smaller->fEndT) {
1636 0 : continue;
1637 : }
1638 0 : SkOPASSERT(test->fStartT != smaller->fEndT);
1639 0 : if (larger && larger->fStartT < test->fStartT) {
1640 0 : continue;
1641 : }
1642 0 : largerPrior = prior;
1643 0 : larger = test;
1644 : } while ((prior = test), (test = test->fNext));
1645 0 : if (!larger) {
1646 0 : continue;
1647 : }
1648 : // check middle t value to see if it is coincident as well
1649 0 : double midT = (smaller->fEndT + larger->fStartT) / 2;
1650 0 : SkDPoint midPt = fCurve.ptAtT(midT);
1651 0 : SkTCoincident<TCurve, OppCurve> coin;
1652 0 : coin.setPerp(fCurve, midT, midPt, sect2->fCurve);
1653 0 : if (coin.isMatch()) {
1654 0 : smaller->fEndT = larger->fEndT;
1655 0 : smaller->fCoinEnd = larger->fCoinEnd;
1656 0 : if (largerPrior) {
1657 0 : largerPrior->fNext = larger->fNext;
1658 0 : largerPrior->validate();
1659 : } else {
1660 0 : fCoincident = larger->fNext;
1661 : }
1662 0 : }
1663 : } while (true);
1664 : }
1665 :
1666 : template<typename TCurve, typename OppCurve>
1667 : SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::prev(
1668 : SkTSpan<TCurve, OppCurve>* span) const {
1669 : SkTSpan<TCurve, OppCurve>* result = nullptr;
1670 : SkTSpan<TCurve, OppCurve>* test = fHead;
1671 : while (span != test) {
1672 : result = test;
1673 : test = test->fNext;
1674 : SkASSERT(test);
1675 : }
1676 : return result;
1677 : }
1678 :
1679 : template<typename TCurve, typename OppCurve>
1680 0 : void SkTSect<TCurve, OppCurve>::recoverCollapsed() {
1681 0 : SkTSpan<TCurve, OppCurve>* deleted = fDeleted;
1682 0 : while (deleted) {
1683 0 : SkTSpan<TCurve, OppCurve>* delNext = deleted->fNext;
1684 0 : if (deleted->fCollapsed) {
1685 0 : SkTSpan<TCurve, OppCurve>** spanPtr = &fHead;
1686 0 : while (*spanPtr && (*spanPtr)->fEndT <= deleted->fStartT) {
1687 0 : spanPtr = &(*spanPtr)->fNext;
1688 : }
1689 0 : deleted->fNext = *spanPtr;
1690 0 : *spanPtr = deleted;
1691 : }
1692 0 : deleted = delNext;
1693 : }
1694 0 : }
1695 :
1696 : template<typename TCurve, typename OppCurve>
1697 0 : void SkTSect<TCurve, OppCurve>::removeAllBut(const SkTSpan<OppCurve, TCurve>* keep,
1698 : SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp) {
1699 0 : const SkTSpanBounded<OppCurve, TCurve>* testBounded = span->fBounded;
1700 0 : while (testBounded) {
1701 0 : SkTSpan<OppCurve, TCurve>* bounded = testBounded->fBounded;
1702 0 : const SkTSpanBounded<OppCurve, TCurve>* next = testBounded->fNext;
1703 : // may have been deleted when opp did 'remove all but'
1704 0 : if (bounded != keep && !bounded->fDeleted) {
1705 0 : SkAssertResult(SkDEBUGCODE(!) span->removeBounded(bounded));
1706 0 : if (bounded->removeBounded(span)) {
1707 0 : opp->removeSpan(bounded);
1708 : }
1709 : }
1710 0 : testBounded = next;
1711 : }
1712 0 : SkASSERT(!span->fDeleted);
1713 0 : SkASSERT(span->findOppSpan(keep));
1714 0 : SkASSERT(keep->findOppSpan(span));
1715 0 : }
1716 :
1717 : template<typename TCurve, typename OppCurve>
1718 0 : void SkTSect<TCurve, OppCurve>::removeByPerpendicular(SkTSect<OppCurve, TCurve>* opp) {
1719 0 : SkTSpan<TCurve, OppCurve>* test = fHead;
1720 : SkTSpan<TCurve, OppCurve>* next;
1721 0 : do {
1722 0 : next = test->fNext;
1723 0 : if (test->fCoinStart.perpT() < 0 || test->fCoinEnd.perpT() < 0) {
1724 0 : continue;
1725 : }
1726 0 : SkDVector startV = test->fCoinStart.perpPt() - test->fPart[0];
1727 0 : SkDVector endV = test->fCoinEnd.perpPt() - test->fPart[TCurve::kPointLast];
1728 : #if DEBUG_T_SECT
1729 : SkDebugf("%s startV=(%1.9g,%1.9g) endV=(%1.9g,%1.9g) dot=%1.9g\n", __FUNCTION__,
1730 : startV.fX, startV.fY, endV.fX, endV.fY, startV.dot(endV));
1731 : #endif
1732 0 : if (startV.dot(endV) <= 0) {
1733 0 : continue;
1734 : }
1735 0 : this->removeSpans(test, opp);
1736 : } while ((test = next));
1737 0 : }
1738 :
1739 : template<typename TCurve, typename OppCurve>
1740 0 : void SkTSect<TCurve, OppCurve>::removeCoincident(SkTSpan<TCurve, OppCurve>* span, bool isBetween) {
1741 0 : this->unlinkSpan(span);
1742 0 : if (isBetween || between(0, span->fCoinStart.perpT(), 1)) {
1743 0 : --fActiveCount;
1744 0 : span->fNext = fCoincident;
1745 0 : fCoincident = span;
1746 : } else {
1747 0 : this->markSpanGone(span);
1748 : }
1749 0 : }
1750 :
1751 : template<typename TCurve, typename OppCurve>
1752 0 : void SkTSect<TCurve, OppCurve>::removedEndCheck(SkTSpan<TCurve, OppCurve>* span) {
1753 0 : if (!span->fStartT) {
1754 0 : fRemovedStartT = true;
1755 : }
1756 0 : if (1 == span->fEndT) {
1757 0 : fRemovedEndT = true;
1758 : }
1759 0 : }
1760 :
1761 : template<typename TCurve, typename OppCurve>
1762 0 : bool SkTSect<TCurve, OppCurve>::removeSpan(SkTSpan<TCurve, OppCurve>* span) {\
1763 0 : this->removedEndCheck(span);
1764 0 : this->unlinkSpan(span);
1765 0 : return this->markSpanGone(span);
1766 : }
1767 :
1768 : template<typename TCurve, typename OppCurve>
1769 0 : void SkTSect<TCurve, OppCurve>::removeSpanRange(SkTSpan<TCurve, OppCurve>* first,
1770 : SkTSpan<TCurve, OppCurve>* last) {
1771 0 : if (first == last) {
1772 0 : return;
1773 : }
1774 0 : SkTSpan<TCurve, OppCurve>* span = first;
1775 0 : SkASSERT(span);
1776 0 : SkTSpan<TCurve, OppCurve>* final = last->fNext;
1777 0 : SkTSpan<TCurve, OppCurve>* next = span->fNext;
1778 0 : while ((span = next) && span != final) {
1779 0 : next = span->fNext;
1780 0 : this->markSpanGone(span);
1781 : }
1782 0 : if (final) {
1783 0 : final->fPrev = first;
1784 : }
1785 0 : first->fNext = final;
1786 0 : first->validate();
1787 : }
1788 :
1789 : template<typename TCurve, typename OppCurve>
1790 0 : void SkTSect<TCurve, OppCurve>::removeSpans(SkTSpan<TCurve, OppCurve>* span,
1791 : SkTSect<OppCurve, TCurve>* opp) {
1792 0 : SkTSpanBounded<OppCurve, TCurve>* bounded = span->fBounded;
1793 0 : while (bounded) {
1794 0 : SkTSpan<OppCurve, TCurve>* spanBounded = bounded->fBounded;
1795 0 : SkTSpanBounded<OppCurve, TCurve>* next = bounded->fNext;
1796 0 : if (span->removeBounded(spanBounded)) { // shuffles last into position 0
1797 0 : this->removeSpan(span);
1798 : }
1799 0 : if (spanBounded->removeBounded(span)) {
1800 0 : opp->removeSpan(spanBounded);
1801 : }
1802 0 : SkASSERT(!span->fDeleted || !opp->debugHasBounded(span));
1803 0 : bounded = next;
1804 : }
1805 0 : }
1806 :
1807 : template<typename TCurve, typename OppCurve>
1808 0 : SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::spanAtT(double t,
1809 : SkTSpan<TCurve, OppCurve>** priorSpan) {
1810 0 : SkTSpan<TCurve, OppCurve>* test = fHead;
1811 0 : SkTSpan<TCurve, OppCurve>* prev = nullptr;
1812 0 : while (test && test->fEndT < t) {
1813 0 : prev = test;
1814 0 : test = test->fNext;
1815 : }
1816 0 : *priorSpan = prev;
1817 0 : return test && test->fStartT <= t ? test : nullptr;
1818 : }
1819 :
1820 : template<typename TCurve, typename OppCurve>
1821 0 : SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::tail() {
1822 0 : SkTSpan<TCurve, OppCurve>* result = fHead;
1823 0 : SkTSpan<TCurve, OppCurve>* next = fHead;
1824 0 : while ((next = next->fNext)) {
1825 0 : if (next->fEndT > result->fEndT) {
1826 0 : result = next;
1827 : }
1828 : }
1829 0 : return result;
1830 : }
1831 :
1832 : /* Each span has a range of opposite spans it intersects. After the span is split in two,
1833 : adjust the range to its new size */
1834 : template<typename TCurve, typename OppCurve>
1835 0 : bool SkTSect<TCurve, OppCurve>::trim(SkTSpan<TCurve, OppCurve>* span,
1836 : SkTSect<OppCurve, TCurve>* opp) {
1837 0 : FAIL_IF(!span->initBounds(fCurve));
1838 0 : const SkTSpanBounded<OppCurve, TCurve>* testBounded = span->fBounded;
1839 0 : while (testBounded) {
1840 0 : SkTSpan<OppCurve, TCurve>* test = testBounded->fBounded;
1841 0 : const SkTSpanBounded<OppCurve, TCurve>* next = testBounded->fNext;
1842 0 : int oppSects, sects = this->intersects(span, opp, test, &oppSects);
1843 0 : if (sects >= 1) {
1844 0 : if (oppSects == 2) {
1845 0 : test->initBounds(opp->fCurve);
1846 0 : opp->removeAllBut(span, test, this);
1847 : }
1848 0 : if (sects == 2) {
1849 0 : span->initBounds(fCurve);
1850 0 : this->removeAllBut(test, span, opp);
1851 0 : return true;
1852 : }
1853 : } else {
1854 0 : if (span->removeBounded(test)) {
1855 0 : this->removeSpan(span);
1856 : }
1857 0 : if (test->removeBounded(span)) {
1858 0 : opp->removeSpan(test);
1859 : }
1860 : }
1861 0 : testBounded = next;
1862 : }
1863 0 : return true;
1864 : }
1865 :
1866 : template<typename TCurve, typename OppCurve>
1867 0 : void SkTSect<TCurve, OppCurve>::unlinkSpan(SkTSpan<TCurve, OppCurve>* span) {
1868 0 : SkTSpan<TCurve, OppCurve>* prev = span->fPrev;
1869 0 : SkTSpan<TCurve, OppCurve>* next = span->fNext;
1870 0 : if (prev) {
1871 0 : prev->fNext = next;
1872 0 : if (next) {
1873 0 : next->fPrev = prev;
1874 0 : next->validate();
1875 : }
1876 : } else {
1877 0 : fHead = next;
1878 0 : if (next) {
1879 0 : next->fPrev = nullptr;
1880 : }
1881 : }
1882 0 : }
1883 :
1884 : template<typename TCurve, typename OppCurve>
1885 0 : bool SkTSect<TCurve, OppCurve>::updateBounded(SkTSpan<TCurve, OppCurve>* first,
1886 : SkTSpan<TCurve, OppCurve>* last, SkTSpan<OppCurve, TCurve>* oppFirst) {
1887 0 : SkTSpan<TCurve, OppCurve>* test = first;
1888 0 : const SkTSpan<TCurve, OppCurve>* final = last->next();
1889 0 : bool deleteSpan = false;
1890 0 : do {
1891 0 : deleteSpan |= test->removeAllBounded();
1892 0 : } while ((test = test->fNext) != final && test);
1893 0 : first->fBounded = nullptr;
1894 0 : first->addBounded(oppFirst, &fHeap);
1895 : // cannot call validate until remove span range is called
1896 0 : return deleteSpan;
1897 : }
1898 :
1899 :
1900 : template<typename TCurve, typename OppCurve>
1901 0 : void SkTSect<TCurve, OppCurve>::validate() const {
1902 : #if DEBUG_VALIDATE
1903 : int count = 0;
1904 : double last = 0;
1905 : if (fHead) {
1906 : const SkTSpan<TCurve, OppCurve>* span = fHead;
1907 : SkASSERT(!span->fPrev);
1908 : const SkTSpan<TCurve, OppCurve>* next;
1909 : do {
1910 : span->validate();
1911 : SkASSERT(span->fStartT >= last);
1912 : last = span->fEndT;
1913 : ++count;
1914 : next = span->fNext;
1915 : SkASSERT(next != span);
1916 : } while ((span = next) != nullptr);
1917 : }
1918 : SkASSERT(count == fActiveCount);
1919 : #endif
1920 : #if DEBUG_T_SECT
1921 : SkASSERT(fActiveCount <= fDebugAllocatedCount);
1922 : int deletedCount = 0;
1923 : const SkTSpan<TCurve, OppCurve>* deleted = fDeleted;
1924 : while (deleted) {
1925 : ++deletedCount;
1926 : deleted = deleted->fNext;
1927 : }
1928 : const SkTSpan<TCurve, OppCurve>* coincident = fCoincident;
1929 : while (coincident) {
1930 : ++deletedCount;
1931 : coincident = coincident->fNext;
1932 : }
1933 : SkASSERT(fActiveCount + deletedCount == fDebugAllocatedCount);
1934 : #endif
1935 0 : }
1936 :
1937 : template<typename TCurve, typename OppCurve>
1938 0 : void SkTSect<TCurve, OppCurve>::validateBounded() const {
1939 : #if DEBUG_VALIDATE
1940 : if (!fHead) {
1941 : return;
1942 : }
1943 : const SkTSpan<TCurve, OppCurve>* span = fHead;
1944 : do {
1945 : span->validateBounded();
1946 : } while ((span = span->fNext) != nullptr);
1947 : #endif
1948 0 : }
1949 :
1950 : template<typename TCurve, typename OppCurve>
1951 0 : int SkTSect<TCurve, OppCurve>::EndsEqual(const SkTSect<TCurve, OppCurve>* sect1,
1952 : const SkTSect<OppCurve, TCurve>* sect2, SkIntersections* intersections) {
1953 0 : int zeroOneSet = 0;
1954 0 : if (sect1->fCurve[0] == sect2->fCurve[0]) {
1955 0 : zeroOneSet |= kZeroS1Set | kZeroS2Set;
1956 0 : intersections->insert(0, 0, sect1->fCurve[0]);
1957 : }
1958 0 : if (sect1->fCurve[0] == sect2->fCurve[OppCurve::kPointLast]) {
1959 0 : zeroOneSet |= kZeroS1Set | kOneS2Set;
1960 0 : intersections->insert(0, 1, sect1->fCurve[0]);
1961 : }
1962 0 : if (sect1->fCurve[TCurve::kPointLast] == sect2->fCurve[0]) {
1963 0 : zeroOneSet |= kOneS1Set | kZeroS2Set;
1964 0 : intersections->insert(1, 0, sect1->fCurve[TCurve::kPointLast]);
1965 : }
1966 0 : if (sect1->fCurve[TCurve::kPointLast] == sect2->fCurve[OppCurve::kPointLast]) {
1967 0 : zeroOneSet |= kOneS1Set | kOneS2Set;
1968 0 : intersections->insert(1, 1, sect1->fCurve[TCurve::kPointLast]);
1969 : }
1970 : // check for zero
1971 0 : if (!(zeroOneSet & (kZeroS1Set | kZeroS2Set))
1972 0 : && sect1->fCurve[0].approximatelyEqual(sect2->fCurve[0])) {
1973 0 : zeroOneSet |= kZeroS1Set | kZeroS2Set;
1974 0 : intersections->insertNear(0, 0, sect1->fCurve[0], sect2->fCurve[0]);
1975 : }
1976 0 : if (!(zeroOneSet & (kZeroS1Set | kOneS2Set))
1977 0 : && sect1->fCurve[0].approximatelyEqual(sect2->fCurve[OppCurve::kPointLast])) {
1978 0 : zeroOneSet |= kZeroS1Set | kOneS2Set;
1979 0 : intersections->insertNear(0, 1, sect1->fCurve[0], sect2->fCurve[OppCurve::kPointLast]);
1980 : }
1981 : // check for one
1982 0 : if (!(zeroOneSet & (kOneS1Set | kZeroS2Set))
1983 0 : && sect1->fCurve[TCurve::kPointLast].approximatelyEqual(sect2->fCurve[0])) {
1984 0 : zeroOneSet |= kOneS1Set | kZeroS2Set;
1985 0 : intersections->insertNear(1, 0, sect1->fCurve[TCurve::kPointLast], sect2->fCurve[0]);
1986 : }
1987 0 : if (!(zeroOneSet & (kOneS1Set | kOneS2Set))
1988 0 : && sect1->fCurve[TCurve::kPointLast].approximatelyEqual(sect2->fCurve[
1989 : OppCurve::kPointLast])) {
1990 0 : zeroOneSet |= kOneS1Set | kOneS2Set;
1991 0 : intersections->insertNear(1, 1, sect1->fCurve[TCurve::kPointLast],
1992 0 : sect2->fCurve[OppCurve::kPointLast]);
1993 : }
1994 0 : return zeroOneSet;
1995 : }
1996 :
1997 : template<typename TCurve, typename OppCurve>
1998 : struct SkClosestRecord {
1999 0 : bool operator<(const SkClosestRecord& rh) const {
2000 0 : return fClosest < rh.fClosest;
2001 : }
2002 :
2003 0 : void addIntersection(SkIntersections* intersections) const {
2004 0 : double r1t = fC1Index ? fC1Span->endT() : fC1Span->startT();
2005 0 : double r2t = fC2Index ? fC2Span->endT() : fC2Span->startT();
2006 0 : intersections->insert(r1t, r2t, fC1Span->part()[fC1Index]);
2007 0 : }
2008 :
2009 0 : void findEnd(const SkTSpan<TCurve, OppCurve>* span1, const SkTSpan<OppCurve, TCurve>* span2,
2010 : int c1Index, int c2Index) {
2011 0 : const TCurve& c1 = span1->part();
2012 0 : const OppCurve& c2 = span2->part();
2013 0 : if (!c1[c1Index].approximatelyEqual(c2[c2Index])) {
2014 0 : return;
2015 : }
2016 0 : double dist = c1[c1Index].distanceSquared(c2[c2Index]);
2017 0 : if (fClosest < dist) {
2018 0 : return;
2019 : }
2020 0 : fC1Span = span1;
2021 0 : fC2Span = span2;
2022 0 : fC1StartT = span1->startT();
2023 0 : fC1EndT = span1->endT();
2024 0 : fC2StartT = span2->startT();
2025 0 : fC2EndT = span2->endT();
2026 0 : fC1Index = c1Index;
2027 0 : fC2Index = c2Index;
2028 0 : fClosest = dist;
2029 : }
2030 :
2031 0 : bool matesWith(const SkClosestRecord& mate SkDEBUGPARAMS(SkIntersections* i)) const {
2032 0 : SkOPOBJASSERT(i, fC1Span == mate.fC1Span || fC1Span->endT() <= mate.fC1Span->startT()
2033 : || mate.fC1Span->endT() <= fC1Span->startT());
2034 0 : SkOPOBJASSERT(i, fC2Span == mate.fC2Span || fC2Span->endT() <= mate.fC2Span->startT()
2035 : || mate.fC2Span->endT() <= fC2Span->startT());
2036 0 : return fC1Span == mate.fC1Span || fC1Span->endT() == mate.fC1Span->startT()
2037 0 : || fC1Span->startT() == mate.fC1Span->endT()
2038 0 : || fC2Span == mate.fC2Span
2039 0 : || fC2Span->endT() == mate.fC2Span->startT()
2040 0 : || fC2Span->startT() == mate.fC2Span->endT();
2041 : }
2042 :
2043 0 : void merge(const SkClosestRecord& mate) {
2044 0 : fC1Span = mate.fC1Span;
2045 0 : fC2Span = mate.fC2Span;
2046 0 : fClosest = mate.fClosest;
2047 0 : fC1Index = mate.fC1Index;
2048 0 : fC2Index = mate.fC2Index;
2049 0 : }
2050 :
2051 0 : void reset() {
2052 0 : fClosest = FLT_MAX;
2053 0 : SkDEBUGCODE(fC1Span = nullptr);
2054 0 : SkDEBUGCODE(fC2Span = nullptr);
2055 0 : SkDEBUGCODE(fC1Index = fC2Index = -1);
2056 0 : }
2057 :
2058 0 : void update(const SkClosestRecord& mate) {
2059 0 : fC1StartT = SkTMin(fC1StartT, mate.fC1StartT);
2060 0 : fC1EndT = SkTMax(fC1EndT, mate.fC1EndT);
2061 0 : fC2StartT = SkTMin(fC2StartT, mate.fC2StartT);
2062 0 : fC2EndT = SkTMax(fC2EndT, mate.fC2EndT);
2063 0 : }
2064 :
2065 : const SkTSpan<TCurve, OppCurve>* fC1Span;
2066 : const SkTSpan<OppCurve, TCurve>* fC2Span;
2067 : double fC1StartT;
2068 : double fC1EndT;
2069 : double fC2StartT;
2070 : double fC2EndT;
2071 : double fClosest;
2072 : int fC1Index;
2073 : int fC2Index;
2074 : };
2075 :
2076 : template<typename TCurve, typename OppCurve>
2077 0 : struct SkClosestSect {
2078 0 : SkClosestSect()
2079 0 : : fUsed(0) {
2080 0 : fClosest.push_back().reset();
2081 0 : }
2082 :
2083 0 : bool find(const SkTSpan<TCurve, OppCurve>* span1, const SkTSpan<OppCurve, TCurve>* span2
2084 : SkDEBUGPARAMS(SkIntersections* i)) {
2085 0 : SkClosestRecord<TCurve, OppCurve>* record = &fClosest[fUsed];
2086 0 : record->findEnd(span1, span2, 0, 0);
2087 0 : record->findEnd(span1, span2, 0, OppCurve::kPointLast);
2088 0 : record->findEnd(span1, span2, TCurve::kPointLast, 0);
2089 0 : record->findEnd(span1, span2, TCurve::kPointLast, OppCurve::kPointLast);
2090 0 : if (record->fClosest == FLT_MAX) {
2091 0 : return false;
2092 : }
2093 0 : for (int index = 0; index < fUsed; ++index) {
2094 0 : SkClosestRecord<TCurve, OppCurve>* test = &fClosest[index];
2095 0 : if (test->matesWith(*record SkDEBUGPARAMS(i))) {
2096 0 : if (test->fClosest > record->fClosest) {
2097 0 : test->merge(*record);
2098 : }
2099 0 : test->update(*record);
2100 0 : record->reset();
2101 0 : return false;
2102 : }
2103 : }
2104 0 : ++fUsed;
2105 0 : fClosest.push_back().reset();
2106 0 : return true;
2107 : }
2108 :
2109 0 : void finish(SkIntersections* intersections) const {
2110 : SkSTArray<TCurve::kMaxIntersections * 3,
2111 0 : const SkClosestRecord<TCurve, OppCurve>*, true> closestPtrs;
2112 0 : for (int index = 0; index < fUsed; ++index) {
2113 0 : closestPtrs.push_back(&fClosest[index]);
2114 : }
2115 0 : SkTQSort<const SkClosestRecord<TCurve, OppCurve> >(closestPtrs.begin(), closestPtrs.end()
2116 0 : - 1);
2117 0 : for (int index = 0; index < fUsed; ++index) {
2118 0 : const SkClosestRecord<TCurve, OppCurve>* test = closestPtrs[index];
2119 0 : test->addIntersection(intersections);
2120 : }
2121 0 : }
2122 :
2123 : // this is oversized so that an extra records can merge into final one
2124 : SkSTArray<TCurve::kMaxIntersections * 2, SkClosestRecord<TCurve, OppCurve>, true> fClosest;
2125 : int fUsed;
2126 : };
2127 :
2128 : // returns true if the rect is too small to consider
2129 : template<typename TCurve, typename OppCurve>
2130 0 : void SkTSect<TCurve, OppCurve>::BinarySearch(SkTSect<TCurve, OppCurve>* sect1,
2131 : SkTSect<OppCurve, TCurve>* sect2, SkIntersections* intersections) {
2132 : #if DEBUG_T_SECT_DUMP > 1
2133 : gDumpTSectNum = 0;
2134 : #endif
2135 0 : SkDEBUGCODE(sect1->fOppSect = sect2);
2136 0 : SkDEBUGCODE(sect2->fOppSect = sect1);
2137 0 : intersections->reset();
2138 0 : intersections->setMax(TCurve::kMaxIntersections + 4); // give extra for slop
2139 0 : SkTSpan<TCurve, OppCurve>* span1 = sect1->fHead;
2140 0 : SkTSpan<OppCurve, TCurve>* span2 = sect2->fHead;
2141 0 : int oppSect, sect = sect1->intersects(span1, sect2, span2, &oppSect);
2142 : // SkASSERT(between(0, sect, 2));
2143 0 : if (!sect) {
2144 0 : return;
2145 : }
2146 0 : if (sect == 2 && oppSect == 2) {
2147 0 : (void) EndsEqual(sect1, sect2, intersections);
2148 0 : return;
2149 : }
2150 0 : span1->addBounded(span2, §1->fHeap);
2151 0 : span2->addBounded(span1, §2->fHeap);
2152 0 : const int kMaxCoinLoopCount = 8;
2153 0 : int coinLoopCount = kMaxCoinLoopCount;
2154 0 : double start1s SK_INIT_TO_AVOID_WARNING;
2155 0 : double start1e SK_INIT_TO_AVOID_WARNING;
2156 : do {
2157 : // find the largest bounds
2158 0 : SkTSpan<TCurve, OppCurve>* largest1 = sect1->boundsMax();
2159 0 : if (!largest1) {
2160 0 : break;
2161 : }
2162 0 : SkTSpan<OppCurve, TCurve>* largest2 = sect2->boundsMax();
2163 : // split it
2164 0 : if (!largest2 || (largest1 && (largest1->fBoundsMax > largest2->fBoundsMax
2165 0 : || (!largest1->fCollapsed && largest2->fCollapsed)))) {
2166 0 : if (largest1->fCollapsed) {
2167 0 : break;
2168 : }
2169 0 : sect1->resetRemovedEnds();
2170 0 : sect2->resetRemovedEnds();
2171 : // trim parts that don't intersect the opposite
2172 0 : SkTSpan<TCurve, OppCurve>* half1 = sect1->addOne();
2173 0 : SkDEBUGCODE(half1->debugSetGlobalState(sect1->globalState()));
2174 0 : if (!half1->split(largest1, §1->fHeap)) {
2175 0 : break;
2176 : }
2177 0 : if (!sect1->trim(largest1, sect2)) {
2178 0 : SkOPOBJASSERT(intersections, 0);
2179 0 : return;
2180 : }
2181 0 : if (!sect1->trim(half1, sect2)) {
2182 0 : SkOPOBJASSERT(intersections, 0);
2183 0 : return;
2184 0 : }
2185 : } else {
2186 0 : if (largest2->fCollapsed) {
2187 0 : break;
2188 : }
2189 0 : sect1->resetRemovedEnds();
2190 0 : sect2->resetRemovedEnds();
2191 : // trim parts that don't intersect the opposite
2192 0 : SkTSpan<OppCurve, TCurve>* half2 = sect2->addOne();
2193 0 : SkDEBUGCODE(half2->debugSetGlobalState(sect2->globalState()));
2194 0 : if (!half2->split(largest2, §2->fHeap)) {
2195 0 : break;
2196 : }
2197 0 : if (!sect2->trim(largest2, sect1)) {
2198 0 : SkOPOBJASSERT(intersections, 0);
2199 0 : return;
2200 : }
2201 0 : if (!sect2->trim(half2, sect1)) {
2202 0 : SkOPOBJASSERT(intersections, 0);
2203 0 : return;
2204 : }
2205 : }
2206 0 : sect1->validate();
2207 0 : sect2->validate();
2208 : #if DEBUG_T_SECT_LOOP_COUNT
2209 : intersections->debugBumpLoopCount(SkIntersections::kIterations_DebugLoop);
2210 : #endif
2211 : // if there are 9 or more continuous spans on both sects, suspect coincidence
2212 0 : if (sect1->fActiveCount >= COINCIDENT_SPAN_COUNT
2213 0 : && sect2->fActiveCount >= COINCIDENT_SPAN_COUNT) {
2214 0 : if (coinLoopCount == kMaxCoinLoopCount) {
2215 0 : start1s = sect1->fHead->fStartT;
2216 0 : start1e = sect1->tail()->fEndT;
2217 : }
2218 0 : if (!sect1->coincidentCheck(sect2)) {
2219 0 : return;
2220 : }
2221 0 : sect1->validate();
2222 0 : sect2->validate();
2223 : #if DEBUG_T_SECT_LOOP_COUNT
2224 : intersections->debugBumpLoopCount(SkIntersections::kCoinCheck_DebugLoop);
2225 : #endif
2226 0 : if (!--coinLoopCount && sect1->fHead && sect2->fHead) {
2227 : /* All known working cases resolve in two tries. Sadly, cubicConicTests[0]
2228 : gets stuck in a loop. It adds an extension to allow a coincident end
2229 : perpendicular to track its intersection in the opposite curve. However,
2230 : the bounding box of the extension does not intersect the original curve,
2231 : so the extension is discarded, only to be added again the next time around. */
2232 0 : sect1->coincidentForce(sect2, start1s, start1e);
2233 0 : sect1->validate();
2234 0 : sect2->validate();
2235 : }
2236 : }
2237 0 : if (sect1->fActiveCount >= COINCIDENT_SPAN_COUNT
2238 0 : && sect2->fActiveCount >= COINCIDENT_SPAN_COUNT) {
2239 0 : if (!sect1->fHead) {
2240 0 : return;
2241 : }
2242 0 : sect1->computePerpendiculars(sect2, sect1->fHead, sect1->tail());
2243 0 : if (!sect2->fHead) {
2244 0 : return;
2245 : }
2246 0 : sect2->computePerpendiculars(sect1, sect2->fHead, sect2->tail());
2247 0 : sect1->removeByPerpendicular(sect2);
2248 0 : sect1->validate();
2249 0 : sect2->validate();
2250 : #if DEBUG_T_SECT_LOOP_COUNT
2251 : intersections->debugBumpLoopCount(SkIntersections::kComputePerp_DebugLoop);
2252 : #endif
2253 0 : if (sect1->collapsed() > TCurve::kMaxIntersections) {
2254 0 : break;
2255 : }
2256 : }
2257 : #if DEBUG_T_SECT_DUMP
2258 : sect1->dumpBoth(sect2);
2259 : #endif
2260 0 : if (!sect1->fHead || !sect2->fHead) {
2261 : break;
2262 0 : }
2263 : } while (true);
2264 0 : SkTSpan<TCurve, OppCurve>* coincident = sect1->fCoincident;
2265 0 : if (coincident) {
2266 : // if there is more than one coincident span, check loosely to see if they should be joined
2267 0 : if (coincident->fNext) {
2268 0 : sect1->mergeCoincidence(sect2);
2269 0 : coincident = sect1->fCoincident;
2270 : }
2271 0 : SkASSERT(sect2->fCoincident); // courtesy check : coincidence only looks at sect 1
2272 0 : do {
2273 0 : if (!coincident) {
2274 0 : return;
2275 : }
2276 0 : if (!coincident->fCoinStart.isMatch()) {
2277 0 : continue;
2278 : }
2279 0 : if (!coincident->fCoinEnd.isMatch()) {
2280 0 : continue;
2281 : }
2282 0 : double perpT = coincident->fCoinStart.perpT();
2283 0 : if (perpT < 0) {
2284 0 : return;
2285 : }
2286 : int index = intersections->insertCoincident(coincident->fStartT,
2287 0 : perpT, coincident->fPart[0]);
2288 0 : if ((intersections->insertCoincident(coincident->fEndT,
2289 : coincident->fCoinEnd.perpT(),
2290 0 : coincident->fPart[TCurve::kPointLast]) < 0) && index >= 0) {
2291 0 : intersections->clearCoincidence(index);
2292 : }
2293 : } while ((coincident = coincident->fNext));
2294 : }
2295 0 : int zeroOneSet = EndsEqual(sect1, sect2, intersections);
2296 : // if (!sect1->fHead || !sect2->fHead) {
2297 : // if the final iteration contains an end (0 or 1),
2298 0 : if (sect1->fRemovedStartT && !(zeroOneSet & kZeroS1Set)) {
2299 0 : SkTCoincident<TCurve, OppCurve> perp; // intersect perpendicular with opposite curve
2300 0 : perp.setPerp(sect1->fCurve, 0, sect1->fCurve[0], sect2->fCurve);
2301 0 : if (perp.isMatch()) {
2302 0 : intersections->insert(0, perp.perpT(), perp.perpPt());
2303 : }
2304 : }
2305 0 : if (sect1->fRemovedEndT && !(zeroOneSet & kOneS1Set)) {
2306 0 : SkTCoincident<TCurve, OppCurve> perp;
2307 0 : perp.setPerp(sect1->fCurve, 1, sect1->fCurve[TCurve::kPointLast], sect2->fCurve);
2308 0 : if (perp.isMatch()) {
2309 0 : intersections->insert(1, perp.perpT(), perp.perpPt());
2310 : }
2311 : }
2312 0 : if (sect2->fRemovedStartT && !(zeroOneSet & kZeroS2Set)) {
2313 0 : SkTCoincident<OppCurve, TCurve> perp;
2314 0 : perp.setPerp(sect2->fCurve, 0, sect2->fCurve[0], sect1->fCurve);
2315 0 : if (perp.isMatch()) {
2316 0 : intersections->insert(perp.perpT(), 0, perp.perpPt());
2317 : }
2318 : }
2319 0 : if (sect2->fRemovedEndT && !(zeroOneSet & kOneS2Set)) {
2320 0 : SkTCoincident<OppCurve, TCurve> perp;
2321 0 : perp.setPerp(sect2->fCurve, 1, sect2->fCurve[OppCurve::kPointLast], sect1->fCurve);
2322 0 : if (perp.isMatch()) {
2323 0 : intersections->insert(perp.perpT(), 1, perp.perpPt());
2324 : }
2325 : }
2326 : // }
2327 0 : if (!sect1->fHead || !sect2->fHead) {
2328 0 : return;
2329 : }
2330 0 : sect1->recoverCollapsed();
2331 0 : sect2->recoverCollapsed();
2332 0 : SkTSpan<TCurve, OppCurve>* result1 = sect1->fHead;
2333 : // check heads and tails for zero and ones and insert them if we haven't already done so
2334 0 : const SkTSpan<TCurve, OppCurve>* head1 = result1;
2335 0 : if (!(zeroOneSet & kZeroS1Set) && approximately_less_than_zero(head1->fStartT)) {
2336 0 : const SkDPoint& start1 = sect1->fCurve[0];
2337 0 : if (head1->isBounded()) {
2338 0 : double t = head1->closestBoundedT(start1);
2339 0 : if (sect2->fCurve.ptAtT(t).approximatelyEqual(start1)) {
2340 0 : intersections->insert(0, t, start1);
2341 : }
2342 : }
2343 : }
2344 0 : const SkTSpan<OppCurve, TCurve>* head2 = sect2->fHead;
2345 0 : if (!(zeroOneSet & kZeroS2Set) && approximately_less_than_zero(head2->fStartT)) {
2346 0 : const SkDPoint& start2 = sect2->fCurve[0];
2347 0 : if (head2->isBounded()) {
2348 0 : double t = head2->closestBoundedT(start2);
2349 0 : if (sect1->fCurve.ptAtT(t).approximatelyEqual(start2)) {
2350 0 : intersections->insert(t, 0, start2);
2351 : }
2352 : }
2353 : }
2354 0 : const SkTSpan<TCurve, OppCurve>* tail1 = sect1->tail();
2355 0 : if (!(zeroOneSet & kOneS1Set) && approximately_greater_than_one(tail1->fEndT)) {
2356 0 : const SkDPoint& end1 = sect1->fCurve[TCurve::kPointLast];
2357 0 : if (tail1->isBounded()) {
2358 0 : double t = tail1->closestBoundedT(end1);
2359 0 : if (sect2->fCurve.ptAtT(t).approximatelyEqual(end1)) {
2360 0 : intersections->insert(1, t, end1);
2361 : }
2362 : }
2363 : }
2364 0 : const SkTSpan<OppCurve, TCurve>* tail2 = sect2->tail();
2365 0 : if (!(zeroOneSet & kOneS2Set) && approximately_greater_than_one(tail2->fEndT)) {
2366 0 : const SkDPoint& end2 = sect2->fCurve[OppCurve::kPointLast];
2367 0 : if (tail2->isBounded()) {
2368 0 : double t = tail2->closestBoundedT(end2);
2369 0 : if (sect1->fCurve.ptAtT(t).approximatelyEqual(end2)) {
2370 0 : intersections->insert(t, 1, end2);
2371 : }
2372 : }
2373 : }
2374 0 : SkClosestSect<TCurve, OppCurve> closest;
2375 0 : do {
2376 0 : while (result1 && result1->fCoinStart.isMatch() && result1->fCoinEnd.isMatch()) {
2377 0 : result1 = result1->fNext;
2378 : }
2379 0 : if (!result1) {
2380 0 : break;
2381 : }
2382 0 : SkTSpan<OppCurve, TCurve>* result2 = sect2->fHead;
2383 0 : bool found = false;
2384 0 : while (result2) {
2385 0 : found |= closest.find(result1, result2 SkDEBUGPARAMS(intersections));
2386 0 : result2 = result2->fNext;
2387 : }
2388 : } while ((result1 = result1->fNext));
2389 0 : closest.finish(intersections);
2390 : // if there is more than one intersection and it isn't already coincident, check
2391 0 : int last = intersections->used() - 1;
2392 0 : for (int index = 0; index < last; ) {
2393 0 : if (intersections->isCoincident(index) && intersections->isCoincident(index + 1)) {
2394 0 : ++index;
2395 0 : continue;
2396 : }
2397 0 : double midT = ((*intersections)[0][index] + (*intersections)[0][index + 1]) / 2;
2398 0 : SkDPoint midPt = sect1->fCurve.ptAtT(midT);
2399 : // intersect perpendicular with opposite curve
2400 0 : SkTCoincident<TCurve, OppCurve> perp;
2401 0 : perp.setPerp(sect1->fCurve, midT, midPt, sect2->fCurve);
2402 0 : if (!perp.isMatch()) {
2403 0 : ++index;
2404 0 : continue;
2405 : }
2406 0 : if (intersections->isCoincident(index)) {
2407 0 : intersections->removeOne(index);
2408 0 : --last;
2409 0 : } else if (intersections->isCoincident(index + 1)) {
2410 0 : intersections->removeOne(index + 1);
2411 0 : --last;
2412 : } else {
2413 0 : intersections->setCoincident(index++);
2414 : }
2415 0 : intersections->setCoincident(index);
2416 : }
2417 0 : SkOPOBJASSERT(intersections, intersections->used() <= TCurve::kMaxIntersections);
2418 : }
2419 :
2420 : #endif
|