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