xref: /aosp_15_r20/external/skia/src/pathops/SkIntersections.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2012 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkIntersections.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
11*c8dee2aaSAndroid Build Coastguard Worker 
closestTo(double rangeStart,double rangeEnd,const SkDPoint & testPt,double * closestDist) const12*c8dee2aaSAndroid Build Coastguard Worker int SkIntersections::closestTo(double rangeStart, double rangeEnd, const SkDPoint& testPt,
13*c8dee2aaSAndroid Build Coastguard Worker         double* closestDist) const {
14*c8dee2aaSAndroid Build Coastguard Worker     int closest = -1;
15*c8dee2aaSAndroid Build Coastguard Worker     *closestDist = SK_ScalarMax;
16*c8dee2aaSAndroid Build Coastguard Worker     for (int index = 0; index < fUsed; ++index) {
17*c8dee2aaSAndroid Build Coastguard Worker         if (!between(rangeStart, fT[0][index], rangeEnd)) {
18*c8dee2aaSAndroid Build Coastguard Worker             continue;
19*c8dee2aaSAndroid Build Coastguard Worker         }
20*c8dee2aaSAndroid Build Coastguard Worker         const SkDPoint& iPt = fPt[index];
21*c8dee2aaSAndroid Build Coastguard Worker         double dist = testPt.distanceSquared(iPt);
22*c8dee2aaSAndroid Build Coastguard Worker         if (*closestDist > dist) {
23*c8dee2aaSAndroid Build Coastguard Worker             *closestDist = dist;
24*c8dee2aaSAndroid Build Coastguard Worker             closest = index;
25*c8dee2aaSAndroid Build Coastguard Worker         }
26*c8dee2aaSAndroid Build Coastguard Worker     }
27*c8dee2aaSAndroid Build Coastguard Worker     return closest;
28*c8dee2aaSAndroid Build Coastguard Worker }
29*c8dee2aaSAndroid Build Coastguard Worker 
flip()30*c8dee2aaSAndroid Build Coastguard Worker void SkIntersections::flip() {
31*c8dee2aaSAndroid Build Coastguard Worker     for (int index = 0; index < fUsed; ++index) {
32*c8dee2aaSAndroid Build Coastguard Worker         fT[1][index] = 1 - fT[1][index];
33*c8dee2aaSAndroid Build Coastguard Worker     }
34*c8dee2aaSAndroid Build Coastguard Worker }
35*c8dee2aaSAndroid Build Coastguard Worker 
insert(double one,double two,const SkDPoint & pt)36*c8dee2aaSAndroid Build Coastguard Worker int SkIntersections::insert(double one, double two, const SkDPoint& pt) {
37*c8dee2aaSAndroid Build Coastguard Worker     if (fIsCoincident[0] == 3 && between(fT[0][0], one, fT[0][1])) {
38*c8dee2aaSAndroid Build Coastguard Worker         // For now, don't allow a mix of coincident and non-coincident intersections
39*c8dee2aaSAndroid Build Coastguard Worker         return -1;
40*c8dee2aaSAndroid Build Coastguard Worker     }
41*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fUsed <= 1 || fT[0][0] <= fT[0][1]);
42*c8dee2aaSAndroid Build Coastguard Worker     int index;
43*c8dee2aaSAndroid Build Coastguard Worker     for (index = 0; index < fUsed; ++index) {
44*c8dee2aaSAndroid Build Coastguard Worker         double oldOne = fT[0][index];
45*c8dee2aaSAndroid Build Coastguard Worker         double oldTwo = fT[1][index];
46*c8dee2aaSAndroid Build Coastguard Worker         if (one == oldOne && two == oldTwo) {
47*c8dee2aaSAndroid Build Coastguard Worker             return -1;
48*c8dee2aaSAndroid Build Coastguard Worker         }
49*c8dee2aaSAndroid Build Coastguard Worker         if (more_roughly_equal(oldOne, one) && more_roughly_equal(oldTwo, two)) {
50*c8dee2aaSAndroid Build Coastguard Worker             if ((!precisely_zero(one) || precisely_zero(oldOne))
51*c8dee2aaSAndroid Build Coastguard Worker                     && (!precisely_equal(one, 1) || precisely_equal(oldOne, 1))
52*c8dee2aaSAndroid Build Coastguard Worker                     && (!precisely_zero(two) || precisely_zero(oldTwo))
53*c8dee2aaSAndroid Build Coastguard Worker                     && (!precisely_equal(two, 1) || precisely_equal(oldTwo, 1))) {
54*c8dee2aaSAndroid Build Coastguard Worker                 return -1;
55*c8dee2aaSAndroid Build Coastguard Worker             }
56*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(one >= 0 && one <= 1);
57*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(two >= 0 && two <= 1);
58*c8dee2aaSAndroid Build Coastguard Worker             // remove this and reinsert below in case replacing would make list unsorted
59*c8dee2aaSAndroid Build Coastguard Worker             int remaining = fUsed - index - 1;
60*c8dee2aaSAndroid Build Coastguard Worker             memmove(&fPt[index], &fPt[index + 1], sizeof(fPt[0]) * remaining);
61*c8dee2aaSAndroid Build Coastguard Worker             memmove(&fT[0][index], &fT[0][index + 1], sizeof(fT[0][0]) * remaining);
62*c8dee2aaSAndroid Build Coastguard Worker             memmove(&fT[1][index], &fT[1][index + 1], sizeof(fT[1][0]) * remaining);
63*c8dee2aaSAndroid Build Coastguard Worker             int clearMask = ~((1 << index) - 1);
64*c8dee2aaSAndroid Build Coastguard Worker             fIsCoincident[0] -= (fIsCoincident[0] >> 1) & clearMask;
65*c8dee2aaSAndroid Build Coastguard Worker             fIsCoincident[1] -= (fIsCoincident[1] >> 1) & clearMask;
66*c8dee2aaSAndroid Build Coastguard Worker             --fUsed;
67*c8dee2aaSAndroid Build Coastguard Worker             break;
68*c8dee2aaSAndroid Build Coastguard Worker         }
69*c8dee2aaSAndroid Build Coastguard Worker     #if ONE_OFF_DEBUG
70*c8dee2aaSAndroid Build Coastguard Worker         if (pt.roughlyEqual(fPt[index])) {
71*c8dee2aaSAndroid Build Coastguard Worker             SkDebugf("%s t=%1.9g pts roughly equal\n", __FUNCTION__, one);
72*c8dee2aaSAndroid Build Coastguard Worker         }
73*c8dee2aaSAndroid Build Coastguard Worker     #endif
74*c8dee2aaSAndroid Build Coastguard Worker     }
75*c8dee2aaSAndroid Build Coastguard Worker     for (index = 0; index < fUsed; ++index) {
76*c8dee2aaSAndroid Build Coastguard Worker         if (fT[0][index] > one) {
77*c8dee2aaSAndroid Build Coastguard Worker             break;
78*c8dee2aaSAndroid Build Coastguard Worker         }
79*c8dee2aaSAndroid Build Coastguard Worker     }
80*c8dee2aaSAndroid Build Coastguard Worker     if (fUsed >= fMax) {
81*c8dee2aaSAndroid Build Coastguard Worker         SkOPASSERT(0);  // FIXME : this error, if it is to be handled at runtime in release, must
82*c8dee2aaSAndroid Build Coastguard Worker                       // be propagated all the way back down to the caller, and return failure.
83*c8dee2aaSAndroid Build Coastguard Worker         fUsed = 0;
84*c8dee2aaSAndroid Build Coastguard Worker         return 0;
85*c8dee2aaSAndroid Build Coastguard Worker     }
86*c8dee2aaSAndroid Build Coastguard Worker     int remaining = fUsed - index;
87*c8dee2aaSAndroid Build Coastguard Worker     if (remaining > 0) {
88*c8dee2aaSAndroid Build Coastguard Worker         memmove(&fPt[index + 1], &fPt[index], sizeof(fPt[0]) * remaining);
89*c8dee2aaSAndroid Build Coastguard Worker         memmove(&fT[0][index + 1], &fT[0][index], sizeof(fT[0][0]) * remaining);
90*c8dee2aaSAndroid Build Coastguard Worker         memmove(&fT[1][index + 1], &fT[1][index], sizeof(fT[1][0]) * remaining);
91*c8dee2aaSAndroid Build Coastguard Worker         int clearMask = ~((1 << index) - 1);
92*c8dee2aaSAndroid Build Coastguard Worker         fIsCoincident[0] += fIsCoincident[0] & clearMask;
93*c8dee2aaSAndroid Build Coastguard Worker         fIsCoincident[1] += fIsCoincident[1] & clearMask;
94*c8dee2aaSAndroid Build Coastguard Worker     }
95*c8dee2aaSAndroid Build Coastguard Worker     fPt[index] = pt;
96*c8dee2aaSAndroid Build Coastguard Worker     if (one < 0 || one > 1) {
97*c8dee2aaSAndroid Build Coastguard Worker         return -1;
98*c8dee2aaSAndroid Build Coastguard Worker     }
99*c8dee2aaSAndroid Build Coastguard Worker     if (two < 0 || two > 1) {
100*c8dee2aaSAndroid Build Coastguard Worker         return -1;
101*c8dee2aaSAndroid Build Coastguard Worker     }
102*c8dee2aaSAndroid Build Coastguard Worker     fT[0][index] = one;
103*c8dee2aaSAndroid Build Coastguard Worker     fT[1][index] = two;
104*c8dee2aaSAndroid Build Coastguard Worker     ++fUsed;
105*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fUsed <= std::size(fPt));
106*c8dee2aaSAndroid Build Coastguard Worker     return index;
107*c8dee2aaSAndroid Build Coastguard Worker }
108*c8dee2aaSAndroid Build Coastguard Worker 
insertNear(double one,double two,const SkDPoint & pt1,const SkDPoint & pt2)109*c8dee2aaSAndroid Build Coastguard Worker void SkIntersections::insertNear(double one, double two, const SkDPoint& pt1, const SkDPoint& pt2) {
110*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(one == 0 || one == 1);
111*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(two == 0 || two == 1);
112*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(pt1 != pt2);
113*c8dee2aaSAndroid Build Coastguard Worker     fNearlySame[one ? 1 : 0] = true;
114*c8dee2aaSAndroid Build Coastguard Worker     (void) insert(one, two, pt1);
115*c8dee2aaSAndroid Build Coastguard Worker     fPt2[one ? 1 : 0] = pt2;
116*c8dee2aaSAndroid Build Coastguard Worker }
117*c8dee2aaSAndroid Build Coastguard Worker 
insertCoincident(double one,double two,const SkDPoint & pt)118*c8dee2aaSAndroid Build Coastguard Worker int SkIntersections::insertCoincident(double one, double two, const SkDPoint& pt) {
119*c8dee2aaSAndroid Build Coastguard Worker     int index = insertSwap(one, two, pt);
120*c8dee2aaSAndroid Build Coastguard Worker     if (index >= 0) {
121*c8dee2aaSAndroid Build Coastguard Worker         setCoincident(index);
122*c8dee2aaSAndroid Build Coastguard Worker     }
123*c8dee2aaSAndroid Build Coastguard Worker     return index;
124*c8dee2aaSAndroid Build Coastguard Worker }
125*c8dee2aaSAndroid Build Coastguard Worker 
setCoincident(int index)126*c8dee2aaSAndroid Build Coastguard Worker void SkIntersections::setCoincident(int index) {
127*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(index >= 0);
128*c8dee2aaSAndroid Build Coastguard Worker     int bit = 1 << index;
129*c8dee2aaSAndroid Build Coastguard Worker     fIsCoincident[0] |= bit;
130*c8dee2aaSAndroid Build Coastguard Worker     fIsCoincident[1] |= bit;
131*c8dee2aaSAndroid Build Coastguard Worker }
132*c8dee2aaSAndroid Build Coastguard Worker 
merge(const SkIntersections & a,int aIndex,const SkIntersections & b,int bIndex)133*c8dee2aaSAndroid Build Coastguard Worker void SkIntersections::merge(const SkIntersections& a, int aIndex, const SkIntersections& b,
134*c8dee2aaSAndroid Build Coastguard Worker         int bIndex) {
135*c8dee2aaSAndroid Build Coastguard Worker     this->reset();
136*c8dee2aaSAndroid Build Coastguard Worker     fT[0][0] = a.fT[0][aIndex];
137*c8dee2aaSAndroid Build Coastguard Worker     fT[1][0] = b.fT[0][bIndex];
138*c8dee2aaSAndroid Build Coastguard Worker     fPt[0] = a.fPt[aIndex];
139*c8dee2aaSAndroid Build Coastguard Worker     fPt2[0] = b.fPt[bIndex];
140*c8dee2aaSAndroid Build Coastguard Worker     fUsed = 1;
141*c8dee2aaSAndroid Build Coastguard Worker }
142*c8dee2aaSAndroid Build Coastguard Worker 
mostOutside(double rangeStart,double rangeEnd,const SkDPoint & origin) const143*c8dee2aaSAndroid Build Coastguard Worker int SkIntersections::mostOutside(double rangeStart, double rangeEnd, const SkDPoint& origin) const {
144*c8dee2aaSAndroid Build Coastguard Worker     int result = -1;
145*c8dee2aaSAndroid Build Coastguard Worker     for (int index = 0; index < fUsed; ++index) {
146*c8dee2aaSAndroid Build Coastguard Worker         if (!between(rangeStart, fT[0][index], rangeEnd)) {
147*c8dee2aaSAndroid Build Coastguard Worker             continue;
148*c8dee2aaSAndroid Build Coastguard Worker         }
149*c8dee2aaSAndroid Build Coastguard Worker         if (result < 0) {
150*c8dee2aaSAndroid Build Coastguard Worker             result = index;
151*c8dee2aaSAndroid Build Coastguard Worker             continue;
152*c8dee2aaSAndroid Build Coastguard Worker         }
153*c8dee2aaSAndroid Build Coastguard Worker         SkDVector best = fPt[result] - origin;
154*c8dee2aaSAndroid Build Coastguard Worker         SkDVector test = fPt[index] - origin;
155*c8dee2aaSAndroid Build Coastguard Worker         if (test.crossCheck(best) < 0) {
156*c8dee2aaSAndroid Build Coastguard Worker             result = index;
157*c8dee2aaSAndroid Build Coastguard Worker         }
158*c8dee2aaSAndroid Build Coastguard Worker     }
159*c8dee2aaSAndroid Build Coastguard Worker     return result;
160*c8dee2aaSAndroid Build Coastguard Worker }
161*c8dee2aaSAndroid Build Coastguard Worker 
removeOne(int index)162*c8dee2aaSAndroid Build Coastguard Worker void SkIntersections::removeOne(int index) {
163*c8dee2aaSAndroid Build Coastguard Worker     int remaining = --fUsed - index;
164*c8dee2aaSAndroid Build Coastguard Worker     if (remaining <= 0) {
165*c8dee2aaSAndroid Build Coastguard Worker         return;
166*c8dee2aaSAndroid Build Coastguard Worker     }
167*c8dee2aaSAndroid Build Coastguard Worker     memmove(&fPt[index], &fPt[index + 1], sizeof(fPt[0]) * remaining);
168*c8dee2aaSAndroid Build Coastguard Worker     memmove(&fT[0][index], &fT[0][index + 1], sizeof(fT[0][0]) * remaining);
169*c8dee2aaSAndroid Build Coastguard Worker     memmove(&fT[1][index], &fT[1][index + 1], sizeof(fT[1][0]) * remaining);
170*c8dee2aaSAndroid Build Coastguard Worker //    SkASSERT(fIsCoincident[0] == 0);
171*c8dee2aaSAndroid Build Coastguard Worker     int coBit = fIsCoincident[0] & (1 << index);
172*c8dee2aaSAndroid Build Coastguard Worker     fIsCoincident[0] -= ((fIsCoincident[0] >> 1) & ~((1 << index) - 1)) + coBit;
173*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!(coBit ^ (fIsCoincident[1] & (1 << index))));
174*c8dee2aaSAndroid Build Coastguard Worker     fIsCoincident[1] -= ((fIsCoincident[1] >> 1) & ~((1 << index) - 1)) + coBit;
175*c8dee2aaSAndroid Build Coastguard Worker }
176