xref: /aosp_15_r20/external/skia/src/pathops/SkPathOpsLine.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 #include "src/pathops/SkPathOpsLine.h"
8*c8dee2aaSAndroid Build Coastguard Worker 
9*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsTypes.h"
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include <cmath>
12*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
13*c8dee2aaSAndroid Build Coastguard Worker 
ptAtT(double t) const14*c8dee2aaSAndroid Build Coastguard Worker SkDPoint SkDLine::ptAtT(double t) const {
15*c8dee2aaSAndroid Build Coastguard Worker     if (0 == t) {
16*c8dee2aaSAndroid Build Coastguard Worker         return fPts[0];
17*c8dee2aaSAndroid Build Coastguard Worker     }
18*c8dee2aaSAndroid Build Coastguard Worker     if (1 == t) {
19*c8dee2aaSAndroid Build Coastguard Worker         return fPts[1];
20*c8dee2aaSAndroid Build Coastguard Worker     }
21*c8dee2aaSAndroid Build Coastguard Worker     double one_t = 1 - t;
22*c8dee2aaSAndroid Build Coastguard Worker     SkDPoint result = { one_t * fPts[0].fX + t * fPts[1].fX, one_t * fPts[0].fY + t * fPts[1].fY };
23*c8dee2aaSAndroid Build Coastguard Worker     return result;
24*c8dee2aaSAndroid Build Coastguard Worker }
25*c8dee2aaSAndroid Build Coastguard Worker 
exactPoint(const SkDPoint & xy) const26*c8dee2aaSAndroid Build Coastguard Worker double SkDLine::exactPoint(const SkDPoint& xy) const {
27*c8dee2aaSAndroid Build Coastguard Worker     if (xy == fPts[0]) {  // do cheapest test first
28*c8dee2aaSAndroid Build Coastguard Worker         return 0;
29*c8dee2aaSAndroid Build Coastguard Worker     }
30*c8dee2aaSAndroid Build Coastguard Worker     if (xy == fPts[1]) {
31*c8dee2aaSAndroid Build Coastguard Worker         return 1;
32*c8dee2aaSAndroid Build Coastguard Worker     }
33*c8dee2aaSAndroid Build Coastguard Worker     return -1;
34*c8dee2aaSAndroid Build Coastguard Worker }
35*c8dee2aaSAndroid Build Coastguard Worker 
nearPoint(const SkDPoint & xy,bool * unequal) const36*c8dee2aaSAndroid Build Coastguard Worker double SkDLine::nearPoint(const SkDPoint& xy, bool* unequal) const {
37*c8dee2aaSAndroid Build Coastguard Worker     if (!AlmostBetweenUlps(fPts[0].fX, xy.fX, fPts[1].fX)
38*c8dee2aaSAndroid Build Coastguard Worker             || !AlmostBetweenUlps(fPts[0].fY, xy.fY, fPts[1].fY)) {
39*c8dee2aaSAndroid Build Coastguard Worker         return -1;
40*c8dee2aaSAndroid Build Coastguard Worker     }
41*c8dee2aaSAndroid Build Coastguard Worker     // project a perpendicular ray from the point to the line; find the T on the line
42*c8dee2aaSAndroid Build Coastguard Worker     SkDVector len = fPts[1] - fPts[0]; // the x/y magnitudes of the line
43*c8dee2aaSAndroid Build Coastguard Worker     double denom = len.fX * len.fX + len.fY * len.fY;  // see DLine intersectRay
44*c8dee2aaSAndroid Build Coastguard Worker     SkDVector ab0 = xy - fPts[0];
45*c8dee2aaSAndroid Build Coastguard Worker     double numer = len.fX * ab0.fX + ab0.fY * len.fY;
46*c8dee2aaSAndroid Build Coastguard Worker     if (!between(0, numer, denom)) {
47*c8dee2aaSAndroid Build Coastguard Worker         return -1;
48*c8dee2aaSAndroid Build Coastguard Worker     }
49*c8dee2aaSAndroid Build Coastguard Worker     if (!denom) {
50*c8dee2aaSAndroid Build Coastguard Worker         return 0;
51*c8dee2aaSAndroid Build Coastguard Worker     }
52*c8dee2aaSAndroid Build Coastguard Worker     double t = numer / denom;
53*c8dee2aaSAndroid Build Coastguard Worker     SkDPoint realPt = ptAtT(t);
54*c8dee2aaSAndroid Build Coastguard Worker     double dist = realPt.distance(xy);   // OPTIMIZATION: can we compare against distSq instead ?
55*c8dee2aaSAndroid Build Coastguard Worker     // find the ordinal in the original line with the largest unsigned exponent
56*c8dee2aaSAndroid Build Coastguard Worker     double tiniest = std::min(std::min(std::min(fPts[0].fX, fPts[0].fY), fPts[1].fX), fPts[1].fY);
57*c8dee2aaSAndroid Build Coastguard Worker     double largest = std::max(std::max(std::max(fPts[0].fX, fPts[0].fY), fPts[1].fX), fPts[1].fY);
58*c8dee2aaSAndroid Build Coastguard Worker     largest = std::max(largest, -tiniest);
59*c8dee2aaSAndroid Build Coastguard Worker     if (!AlmostEqualUlps_Pin(largest, largest + dist)) { // is the dist within ULPS tolerance?
60*c8dee2aaSAndroid Build Coastguard Worker         return -1;
61*c8dee2aaSAndroid Build Coastguard Worker     }
62*c8dee2aaSAndroid Build Coastguard Worker     if (unequal) {
63*c8dee2aaSAndroid Build Coastguard Worker         *unequal = (float) largest != (float) (largest + dist);
64*c8dee2aaSAndroid Build Coastguard Worker     }
65*c8dee2aaSAndroid Build Coastguard Worker     t = SkPinT(t);  // a looser pin breaks skpwww_lptemp_com_3
66*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(between(0, t, 1));
67*c8dee2aaSAndroid Build Coastguard Worker     return t;
68*c8dee2aaSAndroid Build Coastguard Worker }
69*c8dee2aaSAndroid Build Coastguard Worker 
nearRay(const SkDPoint & xy) const70*c8dee2aaSAndroid Build Coastguard Worker bool SkDLine::nearRay(const SkDPoint& xy) const {
71*c8dee2aaSAndroid Build Coastguard Worker     // project a perpendicular ray from the point to the line; find the T on the line
72*c8dee2aaSAndroid Build Coastguard Worker     SkDVector len = fPts[1] - fPts[0]; // the x/y magnitudes of the line
73*c8dee2aaSAndroid Build Coastguard Worker     double denom = len.fX * len.fX + len.fY * len.fY;  // see DLine intersectRay
74*c8dee2aaSAndroid Build Coastguard Worker     SkDVector ab0 = xy - fPts[0];
75*c8dee2aaSAndroid Build Coastguard Worker     double numer = len.fX * ab0.fX + ab0.fY * len.fY;
76*c8dee2aaSAndroid Build Coastguard Worker     double t = numer / denom;
77*c8dee2aaSAndroid Build Coastguard Worker     SkDPoint realPt = ptAtT(t);
78*c8dee2aaSAndroid Build Coastguard Worker     double dist = realPt.distance(xy);   // OPTIMIZATION: can we compare against distSq instead ?
79*c8dee2aaSAndroid Build Coastguard Worker     // find the ordinal in the original line with the largest unsigned exponent
80*c8dee2aaSAndroid Build Coastguard Worker     double tiniest = std::min(std::min(std::min(fPts[0].fX, fPts[0].fY), fPts[1].fX), fPts[1].fY);
81*c8dee2aaSAndroid Build Coastguard Worker     double largest = std::max(std::max(std::max(fPts[0].fX, fPts[0].fY), fPts[1].fX), fPts[1].fY);
82*c8dee2aaSAndroid Build Coastguard Worker     largest = std::max(largest, -tiniest);
83*c8dee2aaSAndroid Build Coastguard Worker     return RoughlyEqualUlps(largest, largest + dist); // is the dist within ULPS tolerance?
84*c8dee2aaSAndroid Build Coastguard Worker }
85*c8dee2aaSAndroid Build Coastguard Worker 
ExactPointH(const SkDPoint & xy,double left,double right,double y)86*c8dee2aaSAndroid Build Coastguard Worker double SkDLine::ExactPointH(const SkDPoint& xy, double left, double right, double y) {
87*c8dee2aaSAndroid Build Coastguard Worker     if (xy.fY == y) {
88*c8dee2aaSAndroid Build Coastguard Worker         if (xy.fX == left) {
89*c8dee2aaSAndroid Build Coastguard Worker             return 0;
90*c8dee2aaSAndroid Build Coastguard Worker         }
91*c8dee2aaSAndroid Build Coastguard Worker         if (xy.fX == right) {
92*c8dee2aaSAndroid Build Coastguard Worker             return 1;
93*c8dee2aaSAndroid Build Coastguard Worker         }
94*c8dee2aaSAndroid Build Coastguard Worker     }
95*c8dee2aaSAndroid Build Coastguard Worker     return -1;
96*c8dee2aaSAndroid Build Coastguard Worker }
97*c8dee2aaSAndroid Build Coastguard Worker 
NearPointH(const SkDPoint & xy,double left,double right,double y)98*c8dee2aaSAndroid Build Coastguard Worker double SkDLine::NearPointH(const SkDPoint& xy, double left, double right, double y) {
99*c8dee2aaSAndroid Build Coastguard Worker     if (!AlmostBequalUlps(xy.fY, y)) {
100*c8dee2aaSAndroid Build Coastguard Worker         return -1;
101*c8dee2aaSAndroid Build Coastguard Worker     }
102*c8dee2aaSAndroid Build Coastguard Worker     if (!AlmostBetweenUlps(left, xy.fX, right)) {
103*c8dee2aaSAndroid Build Coastguard Worker         return -1;
104*c8dee2aaSAndroid Build Coastguard Worker     }
105*c8dee2aaSAndroid Build Coastguard Worker     double t = (xy.fX - left) / (right - left);
106*c8dee2aaSAndroid Build Coastguard Worker     t = SkPinT(t);
107*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(between(0, t, 1));
108*c8dee2aaSAndroid Build Coastguard Worker     double realPtX = (1 - t) * left + t * right;
109*c8dee2aaSAndroid Build Coastguard Worker     SkDVector distU = {xy.fY - y, xy.fX - realPtX};
110*c8dee2aaSAndroid Build Coastguard Worker     double distSq = distU.fX * distU.fX + distU.fY * distU.fY;
111*c8dee2aaSAndroid Build Coastguard Worker     double dist = sqrt(distSq); // OPTIMIZATION: can we compare against distSq instead ?
112*c8dee2aaSAndroid Build Coastguard Worker     double tiniest = std::min(std::min(y, left), right);
113*c8dee2aaSAndroid Build Coastguard Worker     double largest = std::max(std::max(y, left), right);
114*c8dee2aaSAndroid Build Coastguard Worker     largest = std::max(largest, -tiniest);
115*c8dee2aaSAndroid Build Coastguard Worker     if (!AlmostEqualUlps(largest, largest + dist)) { // is the dist within ULPS tolerance?
116*c8dee2aaSAndroid Build Coastguard Worker         return -1;
117*c8dee2aaSAndroid Build Coastguard Worker     }
118*c8dee2aaSAndroid Build Coastguard Worker     return t;
119*c8dee2aaSAndroid Build Coastguard Worker }
120*c8dee2aaSAndroid Build Coastguard Worker 
ExactPointV(const SkDPoint & xy,double top,double bottom,double x)121*c8dee2aaSAndroid Build Coastguard Worker double SkDLine::ExactPointV(const SkDPoint& xy, double top, double bottom, double x) {
122*c8dee2aaSAndroid Build Coastguard Worker     if (xy.fX == x) {
123*c8dee2aaSAndroid Build Coastguard Worker         if (xy.fY == top) {
124*c8dee2aaSAndroid Build Coastguard Worker             return 0;
125*c8dee2aaSAndroid Build Coastguard Worker         }
126*c8dee2aaSAndroid Build Coastguard Worker         if (xy.fY == bottom) {
127*c8dee2aaSAndroid Build Coastguard Worker             return 1;
128*c8dee2aaSAndroid Build Coastguard Worker         }
129*c8dee2aaSAndroid Build Coastguard Worker     }
130*c8dee2aaSAndroid Build Coastguard Worker     return -1;
131*c8dee2aaSAndroid Build Coastguard Worker }
132*c8dee2aaSAndroid Build Coastguard Worker 
NearPointV(const SkDPoint & xy,double top,double bottom,double x)133*c8dee2aaSAndroid Build Coastguard Worker double SkDLine::NearPointV(const SkDPoint& xy, double top, double bottom, double x) {
134*c8dee2aaSAndroid Build Coastguard Worker     if (!AlmostBequalUlps(xy.fX, x)) {
135*c8dee2aaSAndroid Build Coastguard Worker         return -1;
136*c8dee2aaSAndroid Build Coastguard Worker     }
137*c8dee2aaSAndroid Build Coastguard Worker     if (!AlmostBetweenUlps(top, xy.fY, bottom)) {
138*c8dee2aaSAndroid Build Coastguard Worker         return -1;
139*c8dee2aaSAndroid Build Coastguard Worker     }
140*c8dee2aaSAndroid Build Coastguard Worker     double t = (xy.fY - top) / (bottom - top);
141*c8dee2aaSAndroid Build Coastguard Worker     t = SkPinT(t);
142*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(between(0, t, 1));
143*c8dee2aaSAndroid Build Coastguard Worker     double realPtY = (1 - t) * top + t * bottom;
144*c8dee2aaSAndroid Build Coastguard Worker     SkDVector distU = {xy.fX - x, xy.fY - realPtY};
145*c8dee2aaSAndroid Build Coastguard Worker     double distSq = distU.fX * distU.fX + distU.fY * distU.fY;
146*c8dee2aaSAndroid Build Coastguard Worker     double dist = sqrt(distSq); // OPTIMIZATION: can we compare against distSq instead ?
147*c8dee2aaSAndroid Build Coastguard Worker     double tiniest = std::min(std::min(x, top), bottom);
148*c8dee2aaSAndroid Build Coastguard Worker     double largest = std::max(std::max(x, top), bottom);
149*c8dee2aaSAndroid Build Coastguard Worker     largest = std::max(largest, -tiniest);
150*c8dee2aaSAndroid Build Coastguard Worker     if (!AlmostEqualUlps(largest, largest + dist)) { // is the dist within ULPS tolerance?
151*c8dee2aaSAndroid Build Coastguard Worker         return -1;
152*c8dee2aaSAndroid Build Coastguard Worker     }
153*c8dee2aaSAndroid Build Coastguard Worker     return t;
154*c8dee2aaSAndroid Build Coastguard Worker }
155