Coverage Report

Created: 2024-09-14 07:19

/src/skia/src/pathops/SkDLineIntersection.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2012 Google Inc.
3
 *
4
 * Use of this source code is governed by a BSD-style license that can be
5
 * found in the LICENSE file.
6
 */
7
#include "include/core/SkTypes.h"
8
#include "src/pathops/SkIntersections.h"
9
#include "src/pathops/SkPathOpsLine.h"
10
#include "src/pathops/SkPathOpsPoint.h"
11
#include "src/pathops/SkPathOpsTypes.h"
12
13
#include <cmath>
14
#include <cstdint>
15
#include <utility>
16
17
78.5M
void SkIntersections::cleanUpParallelLines(bool parallel) {
18
78.7M
    while (fUsed > 2) {
19
206k
        removeOne(1);
20
206k
    }
21
78.5M
    if (fUsed == 2 && !parallel) {
22
3.16M
        bool startMatch = fT[0][0] == 0 || zero_or_one(fT[1][0]);
23
3.16M
        bool endMatch = fT[0][1] == 1 || zero_or_one(fT[1][1]);
24
3.16M
        if ((!startMatch && !endMatch) || approximately_equal(fT[0][0], fT[0][1])) {
25
1.35M
            SkASSERT(startMatch || endMatch);
26
1.35M
            if (startMatch && endMatch && (fT[0][0] != 0 || !zero_or_one(fT[1][0]))
27
1.35M
                    && fT[0][1] == 1 && zero_or_one(fT[1][1])) {
28
311k
                removeOne(0);
29
1.04M
            } else {
30
1.04M
                removeOne(endMatch);
31
1.04M
            }
32
1.35M
        }
33
3.16M
    }
34
78.5M
    if (fUsed == 2) {
35
4.61M
        fIsCoincident[0] = fIsCoincident[1] = 0x03;
36
4.61M
    }
37
78.5M
}
SkIntersections::cleanUpParallelLines(bool)
Line
Count
Source
17
78.5M
void SkIntersections::cleanUpParallelLines(bool parallel) {
18
78.7M
    while (fUsed > 2) {
19
206k
        removeOne(1);
20
206k
    }
21
78.5M
    if (fUsed == 2 && !parallel) {
22
3.16M
        bool startMatch = fT[0][0] == 0 || zero_or_one(fT[1][0]);
23
3.16M
        bool endMatch = fT[0][1] == 1 || zero_or_one(fT[1][1]);
24
3.16M
        if ((!startMatch && !endMatch) || approximately_equal(fT[0][0], fT[0][1])) {
25
1.35M
            SkASSERT(startMatch || endMatch);
26
1.35M
            if (startMatch && endMatch && (fT[0][0] != 0 || !zero_or_one(fT[1][0]))
27
1.35M
                    && fT[0][1] == 1 && zero_or_one(fT[1][1])) {
28
311k
                removeOne(0);
29
1.04M
            } else {
30
1.04M
                removeOne(endMatch);
31
1.04M
            }
32
1.35M
        }
33
3.16M
    }
34
78.5M
    if (fUsed == 2) {
35
4.61M
        fIsCoincident[0] = fIsCoincident[1] = 0x03;
36
4.61M
    }
37
78.5M
}
Unexecuted instantiation: SkIntersections::cleanUpParallelLines(bool)
38
39
20.8M
void SkIntersections::computePoints(const SkDLine& line, int used) {
40
20.8M
    fPt[0] = line.ptAtT(fT[0][0]);
41
20.8M
    if ((fUsed = used) == 2) {
42
1.07M
        fPt[1] = line.ptAtT(fT[0][1]);
43
1.07M
    }
44
20.8M
}
45
46
16.2M
int SkIntersections::intersectRay(const SkDLine& a, const SkDLine& b) {
47
16.2M
    fMax = 2;
48
16.2M
    SkDVector aLen = a[1] - a[0];
49
16.2M
    SkDVector bLen = b[1] - b[0];
50
    /* Slopes match when denom goes to zero:
51
                      axLen / ayLen ==                   bxLen / byLen
52
    (ayLen * byLen) * axLen / ayLen == (ayLen * byLen) * bxLen / byLen
53
             byLen  * axLen         ==  ayLen          * bxLen
54
             byLen  * axLen         -   ayLen          * bxLen == 0 ( == denom )
55
     */
56
16.2M
    double denom = bLen.fY * aLen.fX - aLen.fY * bLen.fX;
57
16.2M
    int used;
58
16.2M
    if (!approximately_zero(denom)) {
59
14.9M
        SkDVector ab0 = a[0] - b[0];
60
14.9M
        double numerA = ab0.fY * bLen.fX - bLen.fY * ab0.fX;
61
14.9M
        double numerB = ab0.fY * aLen.fX - aLen.fY * ab0.fX;
62
14.9M
        numerA /= denom;
63
14.9M
        numerB /= denom;
64
14.9M
        fT[0][0] = numerA;
65
14.9M
        fT[1][0] = numerB;
66
14.9M
        used = 1;
67
14.9M
    } else {
68
       /* See if the axis intercepts match:
69
                  ay - ax * ayLen / axLen  ==          by - bx * ayLen / axLen
70
         axLen * (ay - ax * ayLen / axLen) == axLen * (by - bx * ayLen / axLen)
71
         axLen *  ay - ax * ayLen          == axLen *  by - bx * ayLen
72
        */
73
1.26M
        if (!AlmostEqualUlps(aLen.fX * a[0].fY - aLen.fY * a[0].fX,
74
1.26M
                aLen.fX * b[0].fY - aLen.fY * b[0].fX)) {
75
197k
            return fUsed = 0;
76
197k
        }
77
        // there's no great answer for intersection points for coincident rays, but return something
78
1.07M
        fT[0][0] = fT[1][0] = 0;
79
1.07M
        fT[1][0] = fT[1][1] = 1;
80
1.07M
        used = 2;
81
1.07M
    }
82
16.0M
    computePoints(a, used);
83
16.0M
    return fUsed;
84
16.2M
}
85
86
// note that this only works if both lines are neither horizontal nor vertical
87
57.6M
int SkIntersections::intersect(const SkDLine& a, const SkDLine& b) {
88
57.6M
    fMax = 3;  // note that we clean up so that there is no more than two in the end
89
    // see if end points intersect the opposite line
90
57.6M
    double t;
91
173M
    for (int iA = 0; iA < 2; ++iA) {
92
115M
        if ((t = b.exactPoint(a[iA])) >= 0) {
93
20.4M
            insert(iA, t, a[iA]);
94
20.4M
        }
95
115M
    }
96
173M
    for (int iB = 0; iB < 2; ++iB) {
97
115M
        if ((t = a.exactPoint(b[iB])) >= 0) {
98
20.4M
            insert(t, iB, b[iB]);
99
20.4M
        }
100
115M
    }
101
    /* Determine the intersection point of two line segments
102
       Return FALSE if the lines don't intersect
103
       from: http://paulbourke.net/geometry/lineline2d/ */
104
57.6M
    double axLen = a[1].fX - a[0].fX;
105
57.6M
    double ayLen = a[1].fY - a[0].fY;
106
57.6M
    double bxLen = b[1].fX - b[0].fX;
107
57.6M
    double byLen = b[1].fY - b[0].fY;
108
    /* Slopes match when denom goes to zero:
109
                      axLen / ayLen ==                   bxLen / byLen
110
    (ayLen * byLen) * axLen / ayLen == (ayLen * byLen) * bxLen / byLen
111
             byLen  * axLen         ==  ayLen          * bxLen
112
             byLen  * axLen         -   ayLen          * bxLen == 0 ( == denom )
113
     */
114
57.6M
    double axByLen = axLen * byLen;
115
57.6M
    double ayBxLen = ayLen * bxLen;
116
    // detect parallel lines the same way here and in SkOpAngle operator <
117
    // so that non-parallel means they are also sortable
118
57.6M
    bool unparallel = fAllowNear ? NotAlmostEqualUlps_Pin(axByLen, ayBxLen)
119
57.6M
            : NotAlmostDequalUlps(axByLen, ayBxLen);
120
57.6M
    if (unparallel && fUsed == 0) {
121
20.1M
        double ab0y = a[0].fY - b[0].fY;
122
20.1M
        double ab0x = a[0].fX - b[0].fX;
123
20.1M
        double numerA = ab0y * bxLen - byLen * ab0x;
124
20.1M
        double numerB = ab0y * axLen - ayLen * ab0x;
125
20.1M
        double denom = axByLen - ayBxLen;
126
20.1M
        if (between(0, numerA, denom) && between(0, numerB, denom)) {
127
4.78M
            fT[0][0] = numerA / denom;
128
4.78M
            fT[1][0] = numerB / denom;
129
4.78M
            computePoints(a, 1);
130
4.78M
        }
131
20.1M
    }
132
/* Allow tracking that both sets of end points are near each other -- the lines are entirely
133
   coincident -- even when the end points are not exactly the same.
134
   Mark this as a 'wild card' for the end points, so that either point is considered totally
135
   coincident. Then, avoid folding the lines over each other, but allow either end to mate
136
   to the next set of lines.
137
 */
138
57.6M
    if (fAllowNear || !unparallel) {
139
57.6M
        double aNearB[2];
140
57.6M
        double bNearA[2];
141
57.6M
        bool aNotB[2] = {false, false};
142
57.6M
        bool bNotA[2] = {false, false};
143
57.6M
        int nearCount = 0;
144
173M
        for (int index = 0; index < 2; ++index) {
145
115M
            aNearB[index] = t = b.nearPoint(a[index], &aNotB[index]);
146
115M
            nearCount += t >= 0;
147
115M
            bNearA[index] = t = a.nearPoint(b[index], &bNotA[index]);
148
115M
            nearCount += t >= 0;
149
115M
        }
150
57.6M
        if (nearCount > 0) {
151
            // Skip if each segment contributes to one end point.
152
25.6M
            if (nearCount != 2 || aNotB[0] == aNotB[1]) {
153
76.0M
                for (int iA = 0; iA < 2; ++iA) {
154
50.7M
                    if (!aNotB[iA]) {
155
50.0M
                        continue;
156
50.0M
                    }
157
641k
                    int nearer = aNearB[iA] > 0.5;
158
641k
                    if (!bNotA[nearer]) {
159
639k
                        continue;
160
639k
                    }
161
2.67k
                    SkASSERT(a[iA] != b[nearer]);
162
2.67k
                    SkOPASSERT(iA == (bNearA[nearer] > 0.5));
163
2.67k
                    insertNear(iA, nearer, a[iA], b[nearer]);
164
2.67k
                    aNearB[iA] = -1;
165
2.67k
                    bNearA[nearer] = -1;
166
2.67k
                    nearCount -= 2;
167
2.67k
                }
168
25.3M
            }
169
25.6M
            if (nearCount > 0) {
170
76.8M
                for (int iA = 0; iA < 2; ++iA) {
171
51.2M
                    if (aNearB[iA] >= 0) {
172
23.5M
                        insert(iA, aNearB[iA], a[iA]);
173
23.5M
                    }
174
51.2M
                }
175
76.8M
                for (int iB = 0; iB < 2; ++iB) {
176
51.2M
                    if (bNearA[iB] >= 0) {
177
26.0M
                        insert(bNearA[iB], iB, b[iB]);
178
26.0M
                    }
179
51.2M
                }
180
25.6M
            }
181
25.6M
        }
182
57.6M
    }
183
57.6M
    cleanUpParallelLines(!unparallel);
184
57.6M
    SkASSERT(fUsed <= 2);
185
57.6M
    return fUsed;
186
57.6M
}
187
188
9.96M
static int horizontal_coincident(const SkDLine& line, double y) {
189
9.96M
    double min = line[0].fY;
190
9.96M
    double max = line[1].fY;
191
9.96M
    if (min > max) {
192
4.41M
        using std::swap;
193
4.41M
        swap(min, max);
194
4.41M
    }
195
9.96M
    if (min > y || max < y) {
196
190k
        return 0;
197
190k
    }
198
9.77M
    if (AlmostEqualUlps(min, max) && max - min < fabs(line[0].fX - line[1].fX)) {
199
1.05M
        return 2;
200
1.05M
    }
201
8.71M
    return 1;
202
9.77M
}
203
204
22.7M
double SkIntersections::HorizontalIntercept(const SkDLine& line, double y) {
205
22.7M
    SkASSERT(line[1].fY != line[0].fY);
206
22.7M
    return SkPinT((y - line[0].fY) / (line[1].fY - line[0].fY));
207
22.7M
}
208
209
int SkIntersections::horizontal(const SkDLine& line, double left, double right,
210
9.96M
                                double y, bool flipped) {
211
9.96M
    fMax = 3;  // clean up parallel at the end will limit the result to 2 at the most
212
    // see if end points intersect the opposite line
213
9.96M
    double t;
214
9.96M
    const SkDPoint leftPt = { left, y };
215
9.96M
    if ((t = line.exactPoint(leftPt)) >= 0) {
216
2.21M
        insert(t, (double) flipped, leftPt);
217
2.21M
    }
218
9.96M
    if (left != right) {
219
9.96M
        const SkDPoint rightPt = { right, y };
220
9.96M
        if ((t = line.exactPoint(rightPt)) >= 0) {
221
2.21M
            insert(t, (double) !flipped, rightPt);
222
2.21M
        }
223
29.8M
        for (int index = 0; index < 2; ++index) {
224
19.9M
            if ((t = SkDLine::ExactPointH(line[index], left, right, y)) >= 0) {
225
4.42M
                insert((double) index, flipped ? 1 - t : t, line[index]);
226
4.42M
            }
227
19.9M
        }
228
9.96M
    }
229
9.96M
    int result = horizontal_coincident(line, y);
230
9.96M
    if (result == 1 && fUsed == 0) {
231
5.26M
        fT[0][0] = HorizontalIntercept(line, y);
232
5.26M
        double xIntercept = line[0].fX + fT[0][0] * (line[1].fX - line[0].fX);
233
5.26M
        if (between(left, xIntercept, right)) {
234
1.92M
            fT[1][0] = (xIntercept - left) / (right - left);
235
1.92M
            if (flipped) {
236
                // OPTIMIZATION: ? instead of swapping, pass original line, use [1].fX - [0].fX
237
1.99M
                for (int index = 0; index < result; ++index) {
238
995k
                    fT[1][index] = 1 - fT[1][index];
239
995k
                }
240
995k
            }
241
1.92M
            fPt[0].fX = xIntercept;
242
1.92M
            fPt[0].fY = y;
243
1.92M
            fUsed = 1;
244
1.92M
        }
245
5.26M
    }
246
9.96M
    if (fAllowNear || result == 2) {
247
9.96M
        if ((t = line.nearPoint(leftPt, nullptr)) >= 0) {
248
2.78M
            insert(t, (double) flipped, leftPt);
249
2.78M
        }
250
9.96M
        if (left != right) {
251
9.96M
            const SkDPoint rightPt = { right, y };
252
9.96M
            if ((t = line.nearPoint(rightPt, nullptr)) >= 0) {
253
2.78M
                insert(t, (double) !flipped, rightPt);
254
2.78M
            }
255
29.8M
            for (int index = 0; index < 2; ++index) {
256
19.9M
                if ((t = SkDLine::NearPointH(line[index], left, right, y)) >= 0) {
257
5.21M
                    insert((double) index, flipped ? 1 - t : t, line[index]);
258
5.21M
                }
259
19.9M
            }
260
9.96M
        }
261
9.96M
    }
262
9.96M
    cleanUpParallelLines(result == 2);
263
9.96M
    return fUsed;
264
9.96M
}
265
266
10.9M
static int vertical_coincident(const SkDLine& line, double x) {
267
10.9M
    double min = line[0].fX;
268
10.9M
    double max = line[1].fX;
269
10.9M
    if (min > max) {
270
4.76M
        using std::swap;
271
4.76M
        swap(min, max);
272
4.76M
    }
273
10.9M
    if (!precisely_between(min, x, max)) {
274
148k
        return 0;
275
148k
    }
276
10.8M
    if (AlmostEqualUlps(min, max)) {
277
1.48M
        return 2;
278
1.48M
    }
279
9.32M
    return 1;
280
10.8M
}
281
282
21.0M
double SkIntersections::VerticalIntercept(const SkDLine& line, double x) {
283
21.0M
    SkASSERT(line[1].fX != line[0].fX);
284
21.0M
    return SkPinT((x - line[0].fX) / (line[1].fX - line[0].fX));
285
21.0M
}
286
287
int SkIntersections::vertical(const SkDLine& line, double top, double bottom,
288
10.9M
                              double x, bool flipped) {
289
10.9M
    fMax = 3;  // cleanup parallel lines will bring this back line
290
    // see if end points intersect the opposite line
291
10.9M
    double t;
292
10.9M
    SkDPoint topPt = { x, top };
293
10.9M
    if ((t = line.exactPoint(topPt)) >= 0) {
294
2.65M
        insert(t, (double) flipped, topPt);
295
2.65M
    }
296
10.9M
    if (top != bottom) {
297
10.9M
        SkDPoint bottomPt = { x, bottom };
298
10.9M
        if ((t = line.exactPoint(bottomPt)) >= 0) {
299
2.64M
            insert(t, (double) !flipped, bottomPt);
300
2.64M
        }
301
32.8M
        for (int index = 0; index < 2; ++index) {
302
21.9M
            if ((t = SkDLine::ExactPointV(line[index], top, bottom, x)) >= 0) {
303
5.30M
                insert((double) index, flipped ? 1 - t : t, line[index]);
304
5.30M
            }
305
21.9M
        }
306
10.9M
    }
307
10.9M
    int result = vertical_coincident(line, x);
308
10.9M
    if (result == 1 && fUsed == 0) {
309
5.59M
        fT[0][0] = VerticalIntercept(line, x);
310
5.59M
        double yIntercept = line[0].fY + fT[0][0] * (line[1].fY - line[0].fY);
311
5.59M
        if (between(top, yIntercept, bottom)) {
312
2.28M
            fT[1][0] = (yIntercept - top) / (bottom - top);
313
2.28M
            if (flipped) {
314
                // OPTIMIZATION: instead of swapping, pass original line, use [1].fY - [0].fY
315
2.21M
                for (int index = 0; index < result; ++index) {
316
1.10M
                    fT[1][index] = 1 - fT[1][index];
317
1.10M
                }
318
1.10M
            }
319
2.28M
            fPt[0].fX = x;
320
2.28M
            fPt[0].fY = yIntercept;
321
2.28M
            fUsed = 1;
322
2.28M
        }
323
5.59M
    }
324
10.9M
    if (fAllowNear || result == 2) {
325
10.9M
        if ((t = line.nearPoint(topPt, nullptr)) >= 0) {
326
3.39M
            insert(t, (double) flipped, topPt);
327
3.39M
        }
328
10.9M
        if (top != bottom) {
329
10.9M
            SkDPoint bottomPt = { x, bottom };
330
10.9M
            if ((t = line.nearPoint(bottomPt, nullptr)) >= 0) {
331
3.37M
                insert(t, (double) !flipped, bottomPt);
332
3.37M
            }
333
32.8M
            for (int index = 0; index < 2; ++index) {
334
21.9M
                if ((t = SkDLine::NearPointV(line[index], top, bottom, x)) >= 0) {
335
6.53M
                    insert((double) index, flipped ? 1 - t : t, line[index]);
336
6.53M
                }
337
21.9M
            }
338
10.9M
        }
339
10.9M
    }
340
10.9M
    cleanUpParallelLines(result == 2);
341
10.9M
    SkASSERT(fUsed <= 2);
342
10.9M
    return fUsed;
343
10.9M
}
344