Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Public Types | Public Member Functions | Static Public Member Functions | Public Attributes | Static Public Attributes | List of all members
SkDCubic Struct Reference

#include <SkPathOpsCubic.h>

Public Types

enum  SearchAxis { kXAxis , kYAxis }
 

Public Member Functions

bool collapsed () const
 
bool controlsInside () const
 
const SkDPointoperator[] (int n) const
 
SkDPointoperator[] (int n)
 
void align (int endIndex, int ctrlIndex, SkDPoint *dstPt) const
 
double binarySearch (double min, double max, double axisIntercept, SearchAxis xAxis) const
 
double calcPrecision () const
 
SkDCubicPair chopAt (double t) const
 
int convexHull (char order[kPointCount]) const
 
void debugInit ()
 
void debugSet (const SkDPoint *pts)
 
void dump () const
 
void dumpID (int id) const
 
void dumpInner () const
 
SkDVector dxdyAtT (double t) const
 
bool endsAreExtremaInXOrY () const
 
int findInflections (double tValues[2]) const
 
int findMaxCurvature (double tValues[]) const
 
bool hullIntersects (const SkDCubic &c2, bool *isLinear) const
 
bool hullIntersects (const SkDConic &c, bool *isLinear) const
 
bool hullIntersects (const SkDQuad &c2, bool *isLinear) const
 
bool hullIntersects (const SkDPoint *pts, int ptCount, bool *isLinear) const
 
bool isLinear (int startIndex, int endIndex) const
 
bool monotonicInX () const
 
bool monotonicInY () const
 
void otherPts (int index, const SkDPoint *o1Pts[kPointCount - 1]) const
 
SkDPoint ptAtT (double t) const
 
int searchRoots (double extremes[6], int extrema, double axisIntercept, SearchAxis xAxis, double *validRoots) const
 
bool toFloatPoints (SkPoint *) const
 
int horizontalIntersect (double yIntercept, double roots[3]) const
 
int verticalIntersect (double xIntercept, double roots[3]) const
 
const SkDCubicset (const SkPoint pts[kPointCount] SkDEBUGPARAMS(SkOpGlobalState *state=nullptr))
 
SkDCubic subDivide (double t1, double t2) const
 
void subDivide (double t1, double t2, SkDCubic *c) const
 
void subDivide (const SkDPoint &a, const SkDPoint &d, double t1, double t2, SkDPoint p[2]) const
 
double top (const SkDCubic &dCurve, double startT, double endT, SkDPoint *topPt) const
 
SkDQuad toQuad () const
 

Static Public Member Functions

static bool IsConic ()
 
static void Coefficients (const double *cubic, double *A, double *B, double *C, double *D)
 
static int ComplexBreak (const SkPoint pts[4], SkScalar *t)
 
static int FindExtrema (const double src[], double tValue[2])
 
static int FindInflections (const SkPoint a[kPointCount], double tValues[2])
 
static int maxIntersections ()
 
static int pointCount ()
 
static int pointLast ()
 
static int RootsReal (double A, double B, double C, double D, double t[3])
 
static int RootsValidT (const double A, const double B, const double C, double D, double s[3])
 
static SkDCubic SubDivide (const SkPoint a[kPointCount], double t1, double t2)
 
static void SubDivide (const SkPoint pts[kPointCount], const SkDPoint &a, const SkDPoint &d, double t1, double t2, SkDPoint p[2])
 

Public Attributes

SkDPoint fPts [kPointCount]
 

Static Public Attributes

static const int kPointCount = 4
 
static const int kPointLast = kPointCount - 1
 
static const int kMaxIntersections = 9
 
static const int gPrecisionUnit = 256
 

Detailed Description

Definition at line 29 of file SkPathOpsCubic.h.

Member Enumeration Documentation

◆ SearchAxis

Enumerator
kXAxis 
kYAxis 

Definition at line 34 of file SkPathOpsCubic.h.

34 {
35 kXAxis,
36 kYAxis
37 };

Member Function Documentation

◆ align()

void SkDCubic::align ( int  endIndex,
int  ctrlIndex,
SkDPoint dstPt 
) const

Definition at line 28 of file SkPathOpsCubic.cpp.

28 {
29 if (fPts[endIndex].fX == fPts[ctrlIndex].fX) {
30 dstPt->fX = fPts[endIndex].fX;
31 }
32 if (fPts[endIndex].fY == fPts[ctrlIndex].fY) {
33 dstPt->fY = fPts[endIndex].fY;
34 }
35}
SkDPoint fPts[kPointCount]

◆ binarySearch()

double SkDCubic::binarySearch ( double  min,
double  max,
double  axisIntercept,
SearchAxis  xAxis 
) const

Definition at line 39 of file SkPathOpsCubic.cpp.

40 {
41 double t = (min + max) / 2;
42 double step = (t - min) / 2;
43 SkDPoint cubicAtT = ptAtT(t);
44 double calcPos = (&cubicAtT.fX)[xAxis];
45 double calcDist = calcPos - axisIntercept;
46 do {
47 double priorT = std::max(min, t - step);
48 SkDPoint lessPt = ptAtT(priorT);
49 if (approximately_equal_half(lessPt.fX, cubicAtT.fX)
50 && approximately_equal_half(lessPt.fY, cubicAtT.fY)) {
51 return -1; // binary search found no point at this axis intercept
52 }
53 double lessDist = (&lessPt.fX)[xAxis] - axisIntercept;
54#if DEBUG_CUBIC_BINARY_SEARCH
55 SkDebugf("t=%1.9g calc=%1.9g dist=%1.9g step=%1.9g less=%1.9g\n", t, calcPos, calcDist,
56 step, lessDist);
57#endif
58 double lastStep = step;
59 step /= 2;
60 if (calcDist > 0 ? calcDist > lessDist : calcDist < lessDist) {
61 t = priorT;
62 } else {
63 double nextT = t + lastStep;
64 if (nextT > max) {
65 return -1;
66 }
67 SkDPoint morePt = ptAtT(nextT);
68 if (approximately_equal_half(morePt.fX, cubicAtT.fX)
69 && approximately_equal_half(morePt.fY, cubicAtT.fY)) {
70 return -1; // binary search found no point at this axis intercept
71 }
72 double moreDist = (&morePt.fX)[xAxis] - axisIntercept;
73 if (calcDist > 0 ? calcDist <= moreDist : calcDist >= moreDist) {
74 continue;
75 }
76 t = nextT;
77 }
78 SkDPoint testAtT = ptAtT(t);
79 cubicAtT = testAtT;
80 calcPos = (&cubicAtT.fX)[xAxis];
81 calcDist = calcPos - axisIntercept;
82 } while (!approximately_equal(calcPos, axisIntercept));
83 return t;
84}
static int step(int x, SkScalar min, SkScalar max)
Definition BlurTest.cpp:215
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
bool approximately_equal(double x, double y)
bool approximately_equal_half(double x, double y)
static float max(float r, float g, float b)
Definition hsl.cpp:49
static float min(float r, float g, float b)
Definition hsl.cpp:48
SkDPoint ptAtT(double t) const

◆ calcPrecision()

double SkDCubic::calcPrecision ( ) const

Definition at line 87 of file SkPathOpsCubic.cpp.

87 {
88 return ((fPts[1] - fPts[0]).length()
89 + (fPts[2] - fPts[1]).length()
90 + (fPts[3] - fPts[2]).length()) / gPrecisionUnit;
91}
size_t length
static const int gPrecisionUnit

◆ chopAt()

SkDCubicPair SkDCubic::chopAt ( double  t) const

Definition at line 111 of file SkPathOpsCubic.cpp.

111 {
113 if (t == 0.5) {
114 dst.pts[0] = fPts[0];
115 dst.pts[1].fX = (fPts[0].fX + fPts[1].fX) / 2;
116 dst.pts[1].fY = (fPts[0].fY + fPts[1].fY) / 2;
117 dst.pts[2].fX = (fPts[0].fX + 2 * fPts[1].fX + fPts[2].fX) / 4;
118 dst.pts[2].fY = (fPts[0].fY + 2 * fPts[1].fY + fPts[2].fY) / 4;
119 dst.pts[3].fX = (fPts[0].fX + 3 * (fPts[1].fX + fPts[2].fX) + fPts[3].fX) / 8;
120 dst.pts[3].fY = (fPts[0].fY + 3 * (fPts[1].fY + fPts[2].fY) + fPts[3].fY) / 8;
121 dst.pts[4].fX = (fPts[1].fX + 2 * fPts[2].fX + fPts[3].fX) / 4;
122 dst.pts[4].fY = (fPts[1].fY + 2 * fPts[2].fY + fPts[3].fY) / 4;
123 dst.pts[5].fX = (fPts[2].fX + fPts[3].fX) / 2;
124 dst.pts[5].fY = (fPts[2].fY + fPts[3].fY) / 2;
125 dst.pts[6] = fPts[3];
126 return dst;
127 }
128 interp_cubic_coords(&fPts[0].fX, &dst.pts[0].fX, t);
129 interp_cubic_coords(&fPts[0].fY, &dst.pts[0].fY, t);
130 return dst;
131}
static void interp_cubic_coords(const double *src, double *dst, double t)
dst
Definition cp.py:12

◆ Coefficients()

void SkDCubic::Coefficients ( const double *  cubic,
double *  A,
double *  B,
double *  C,
double *  D 
)
static

Definition at line 134 of file SkPathOpsCubic.cpp.

134 {
135 *A = src[6]; // d
136 *B = src[4] * 3; // 3*c
137 *C = src[2] * 3; // 3*b
138 *D = src[0]; // a
139 *A -= *D - *C + *B; // A = -a + 3*b - 3*c + d
140 *B += 3 * *D - 2 * *C; // B = 3*a - 6*b + 3*c
141 *C -= 3 * *D; // C = -3*a + 3*b
142}
#define C(TEST_CATEGORY)
Definition colrv1.cpp:247
#define B

◆ collapsed()

bool SkDCubic::collapsed ( ) const
inline

Definition at line 39 of file SkPathOpsCubic.h.

39 {
42 }
bool approximatelyEqual(const SkDPoint &a) const

◆ ComplexBreak()

int SkDCubic::ComplexBreak ( const SkPoint  pts[4],
SkScalar t 
)
static

Definition at line 254 of file SkPathOpsCubic.cpp.

254 {
256 cubic.set(pointsPtr);
257 if (cubic.monotonicInX() && cubic.monotonicInY()) {
258 return 0;
259 }
260 double tt[2], ss[2];
261 SkCubicType cubicType = SkClassifyCubic(pointsPtr, tt, ss);
262 switch (cubicType) {
263 case SkCubicType::kLoop: {
264 const double &td = tt[0], &te = tt[1], &sd = ss[0], &se = ss[1];
265 if (roughly_between(0, td, sd) && roughly_between(0, te, se)) {
266 t[0] = static_cast<SkScalar>((td * se + te * sd) / (2 * sd * se));
267 return (int) (t[0] > 0 && t[0] < 1);
268 }
269 }
270 [[fallthrough]]; // fall through if no t value found
274 double inflectionTs[2];
275 int infTCount = cubic.findInflections(inflectionTs);
276 double maxCurvature[3];
277 int roots = cubic.findMaxCurvature(maxCurvature);
278 #if DEBUG_CUBIC_SPLIT
279 SkDebugf("%s\n", __FUNCTION__);
280 cubic.dump();
281 for (int index = 0; index < infTCount; ++index) {
282 SkDebugf("inflectionsTs[%d]=%1.9g ", index, inflectionTs[index]);
283 SkDPoint pt = cubic.ptAtT(inflectionTs[index]);
284 SkDVector dPt = cubic.dxdyAtT(inflectionTs[index]);
285 SkDLine perp = {{pt - dPt, pt + dPt}};
286 perp.dump();
287 }
288 for (int index = 0; index < roots; ++index) {
289 SkDebugf("maxCurvature[%d]=%1.9g ", index, maxCurvature[index]);
290 SkDPoint pt = cubic.ptAtT(maxCurvature[index]);
291 SkDVector dPt = cubic.dxdyAtT(maxCurvature[index]);
292 SkDLine perp = {{pt - dPt, pt + dPt}};
293 perp.dump();
294 }
295 #endif
296 if (infTCount == 2) {
297 for (int index = 0; index < roots; ++index) {
298 if (between(inflectionTs[0], maxCurvature[index], inflectionTs[1])) {
299 t[0] = maxCurvature[index];
300 return (int) (t[0] > 0 && t[0] < 1);
301 }
302 }
303 } else {
304 int resultCount = 0;
305 // FIXME: constant found through experimentation -- maybe there's a better way....
306 double precision = cubic.calcPrecision() * 2;
307 for (int index = 0; index < roots; ++index) {
308 double testT = maxCurvature[index];
309 if (0 >= testT || testT >= 1) {
310 continue;
311 }
312 // don't call dxdyAtT since we want (0,0) results
313 SkDVector dPt = { derivative_at_t(&cubic.fPts[0].fX, testT),
314 derivative_at_t(&cubic.fPts[0].fY, testT) };
315 double dPtLen = dPt.length();
316 if (dPtLen < precision) {
317 t[resultCount++] = testT;
318 }
319 }
320 if (!resultCount && infTCount == 1) {
321 t[0] = inflectionTs[0];
322 resultCount = (int) (t[0] > 0 && t[0] < 1);
323 }
324 return resultCount;
325 }
326 break;
327 }
328 default:
329 break;
330 }
331 return 0;
332}
SkCubicType SkClassifyCubic(const SkPoint P[4], double t[2], double s[2], double d[4])
static bool between(SkScalar a, SkScalar b, SkScalar c)
SkCubicType
Definition SkGeometry.h:264
static double derivative_at_t(const double *src, double t)
bool roughly_between(double a, double b, double c)
Type::kYUV Type::kRGBA() int(0.7 *637)
float SkScalar
Definition extension.cpp:12
AI float cubic(float precision, const SkPoint pts[], const VectorXform &vectorXform=VectorXform())
void dump() const
double length() const

◆ controlsInside()

bool SkDCubic::controlsInside ( ) const
inline

Definition at line 44 of file SkPathOpsCubic.h.

44 {
45 SkDVector v01 = fPts[0] - fPts[1];
46 SkDVector v02 = fPts[0] - fPts[2];
47 SkDVector v03 = fPts[0] - fPts[3];
48 SkDVector v13 = fPts[1] - fPts[3];
49 SkDVector v23 = fPts[2] - fPts[3];
50 return v03.dot(v01) > 0 && v03.dot(v02) > 0 && v03.dot(v13) > 0 && v03.dot(v23) > 0;
51 }
double dot(const SkDVector &a) const

◆ convexHull()

int SkDCubic::convexHull ( char  order[kPointCount]) const

Definition at line 60 of file SkOpCubicHull.cpp.

60 {
61 size_t index;
62 // find top point
63 size_t yMin = 0;
64 for (index = 1; index < 4; ++index) {
65 if (fPts[yMin].fY > fPts[index].fY || (fPts[yMin].fY == fPts[index].fY
66 && fPts[yMin].fX > fPts[index].fX)) {
67 yMin = index;
68 }
69 }
70 order[0] = yMin;
71 int midX = -1;
72 int backupYMin = -1;
73 for (int pass = 0; pass < 2; ++pass) {
74 for (index = 0; index < 4; ++index) {
75 if (index == yMin) {
76 continue;
77 }
78 // rotate line from (yMin, index) to axis
79 // see if remaining two points are both above or below
80 // use this to find mid
81 int mask = other_two(yMin, index);
82 int side1 = yMin ^ mask;
83 int side2 = index ^ mask;
84 SkDCubic rotPath;
85 if (!rotate(*this, yMin, index, rotPath)) { // ! if cbc[yMin]==cbc[idx]
86 order[1] = side1;
87 order[2] = side2;
88 return 3;
89 }
90 int sides = side(rotPath[side1].fY - rotPath[yMin].fY);
91 sides ^= side(rotPath[side2].fY - rotPath[yMin].fY);
92 if (sides == 2) { // '2' means one remaining point <0, one >0
93 if (midX >= 0) {
94 // one of the control points is equal to an end point
95 order[0] = 0;
96 order[1] = 3;
97 if (fPts[1] == fPts[0] || fPts[1] == fPts[3]) {
98 order[2] = 2;
99 return 3;
100 }
101 if (fPts[2] == fPts[0] || fPts[2] == fPts[3]) {
102 order[2] = 1;
103 return 3;
104 }
105 // one of the control points may be very nearly but not exactly equal --
106 double dist1_0 = fPts[1].distanceSquared(fPts[0]);
107 double dist1_3 = fPts[1].distanceSquared(fPts[3]);
108 double dist2_0 = fPts[2].distanceSquared(fPts[0]);
109 double dist2_3 = fPts[2].distanceSquared(fPts[3]);
110 double smallest1distSq = std::min(dist1_0, dist1_3);
111 double smallest2distSq = std::min(dist2_0, dist2_3);
112 if (approximately_zero(std::min(smallest1distSq, smallest2distSq))) {
113 order[2] = smallest1distSq < smallest2distSq ? 2 : 1;
114 return 3;
115 }
116 }
117 midX = index;
118 } else if (sides == 0) { // '0' means both to one side or the other
119 backupYMin = index;
120 }
121 }
122 if (midX >= 0) {
123 break;
124 }
125 if (backupYMin < 0) {
126 break;
127 }
128 yMin = backupYMin;
129 backupYMin = -1;
130 }
131 if (midX < 0) {
132 midX = yMin ^ 3; // choose any other point
133 }
134 int mask = other_two(yMin, midX);
135 int least = yMin ^ mask;
136 int most = midX ^ mask;
137 order[0] = yMin;
138 order[1] = least;
139
140 // see if mid value is on same side of line (least, most) as yMin
141 SkDCubic midPath;
142 if (!rotate(*this, least, most, midPath)) { // ! if cbc[least]==cbc[most]
143 order[2] = midX;
144 return 3;
145 }
146 int midSides = side(midPath[yMin].fY - midPath[least].fY);
147 midSides ^= side(midPath[midX].fY - midPath[least].fY);
148 if (midSides != 2) { // if mid point is not between
149 order[2] = most;
150 return 3; // result is a triangle
151 }
152 order[2] = midX;
153 order[3] = most;
154 return 4; // result is a quadralateral
155}
static bool approximately_zero(double x)
Definition SkCubics.cpp:153
static bool rotate(const SkDCubic &cubic, int zero, int index, SkDCubic &rotPath)
static int side(double x)
int other_two(int one, int two)
double distanceSquared(const SkDPoint &a) const

◆ debugInit()

void SkDCubic::debugInit ( )
inline

Definition at line 66 of file SkPathOpsCubic.h.

66 {
67 sk_bzero(fPts, sizeof(fPts));
68 }
static void sk_bzero(void *buffer, size_t size)
Definition SkMalloc.h:105

◆ debugSet()

void SkDCubic::debugSet ( const SkDPoint pts)

Definition at line 712 of file SkPathOpsDebug.cpp.

712 {
713 memcpy(fPts, pts, sizeof(fPts));
714 SkDEBUGCODE(fDebugGlobalState = nullptr);
715}
#define SkDEBUGCODE(...)
Definition SkDebug.h:23

◆ dump()

void SkDCubic::dump ( ) const

Definition at line 104 of file PathOpsDebug.cpp.

104 {
105 this->dumpInner();
106 SkDebugf("}},\n");
107}
void dumpInner() const

◆ dumpID()

void SkDCubic::dumpID ( int  id) const

Definition at line 109 of file PathOpsDebug.cpp.

109 {
110 this->dumpInner();
111 SkDebugf("}");
112 DumpID(id);
113}
void DumpID(const SkDConic &, int id)

◆ dumpInner()

void SkDCubic::dumpInner ( ) const

Definition at line 117 of file PathOpsDebug.cpp.

117 {
118 SkDebugf("{{");
119 int index = 0;
120 do {
121 if (index != 0) {
122 if (double_is_NaN(fPts[index].fX) && double_is_NaN(fPts[index].fY)) {
123 return;
124 }
125 SkDebugf(", ");
126 }
127 fPts[index].dump();
128 } while (++index < 3);
129 if (double_is_NaN(fPts[index].fX) && double_is_NaN(fPts[index].fY)) {
130 return;
131 }
132 SkDebugf(", ");
133 fPts[index].dump();
134}
static bool double_is_NaN(double x)
void dump() const

◆ dxdyAtT()

SkDVector SkDCubic::dxdyAtT ( double  t) const

Definition at line 509 of file SkPathOpsCubic.cpp.

509 {
510 SkDVector result = { derivative_at_t(&fPts[0].fX, t), derivative_at_t(&fPts[0].fY, t) };
511 if (result.fX == 0 && result.fY == 0) {
512 if (t == 0) {
513 result = fPts[2] - fPts[0];
514 } else if (t == 1) {
515 result = fPts[3] - fPts[1];
516 } else {
517 // incomplete
518 SkDebugf("!c");
519 }
520 if (result.fX == 0 && result.fY == 0 && zero_or_one(t)) {
521 result = fPts[3] - fPts[0];
522 }
523 }
524 return result;
525}
bool zero_or_one(double x)
GAsyncResult * result

◆ endsAreExtremaInXOrY()

bool SkDCubic::endsAreExtremaInXOrY ( ) const

Definition at line 144 of file SkPathOpsCubic.cpp.

144 {
145 return (between(fPts[0].fX, fPts[1].fX, fPts[3].fX)
146 && between(fPts[0].fX, fPts[2].fX, fPts[3].fX))
147 || (between(fPts[0].fY, fPts[1].fY, fPts[3].fY)
148 && between(fPts[0].fY, fPts[2].fY, fPts[3].fY));
149}

◆ FindExtrema()

int SkDCubic::FindExtrema ( const double  src[],
double  tValues[2] 
)
static

SkDCubic'(t) = At^2 + Bt + C, where A = 3(-a + 3(b - c) + d) B = 6(a - 2b + c) C = 3(b - a) Solve for t, keeping only those that fit between 0 < t < 1

Definition at line 555 of file SkPathOpsCubic.cpp.

555 {
556 // we divide A,B,C by 3 to simplify
557 double a = src[0];
558 double b = src[2];
559 double c = src[4];
560 double d = src[6];
561 double A = d - a + 3 * (b - c);
562 double B = 2 * (a - b - b + c);
563 double C = b - a;
564
565 return SkDQuad::RootsValidT(A, B, C, tValues);
566}
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition main.cc:19
static bool b
struct MyStruct a[10]
static int RootsValidT(const double A, const double B, const double C, double s[2])

◆ FindInflections()

static int SkDCubic::FindInflections ( const SkPoint  a[kPointCount],
double  tValues[2] 
)
inlinestatic

Definition at line 80 of file SkPathOpsCubic.h.

80 {
82 return cubic.set(a).findInflections(tValues);
83 }

◆ findInflections()

int SkDCubic::findInflections ( double  tValues[2]) const

Definition at line 529 of file SkPathOpsCubic.cpp.

529 {
530 double Ax = fPts[1].fX - fPts[0].fX;
531 double Ay = fPts[1].fY - fPts[0].fY;
532 double Bx = fPts[2].fX - 2 * fPts[1].fX + fPts[0].fX;
533 double By = fPts[2].fY - 2 * fPts[1].fY + fPts[0].fY;
534 double Cx = fPts[3].fX + 3 * (fPts[1].fX - fPts[2].fX) - fPts[0].fX;
535 double Cy = fPts[3].fY + 3 * (fPts[1].fY - fPts[2].fY) - fPts[0].fY;
536 return SkDQuad::RootsValidT(Bx * Cy - By * Cx, Ax * Cy - Ay * Cx, Ax * By - Ay * Bx, tValues);
537}

◆ findMaxCurvature()

int SkDCubic::findMaxCurvature ( double  tValues[]) const

Definition at line 580 of file SkPathOpsCubic.cpp.

580 {
581 double coeffX[4], coeffY[4];
582 int i;
583 formulate_F1DotF2(&fPts[0].fX, coeffX);
584 formulate_F1DotF2(&fPts[0].fY, coeffY);
585 for (i = 0; i < 4; i++) {
586 coeffX[i] = coeffX[i] + coeffY[i];
587 }
588 return RootsValidT(coeffX[0], coeffX[1], coeffX[2], coeffX[3], tValues);
589}
static void formulate_F1DotF2(const SkScalar src[], SkScalar coeff[4])
static int RootsValidT(const double A, const double B, const double C, double D, double s[3])

◆ horizontalIntersect()

int SkDCubic::horizontalIntersect ( double  yIntercept,
double  roots[3] 
) const

Return the number of valid roots (0 < root < 1) for this cubic intersecting the specified horizontal line.

Definition at line 458 of file SkDCubicLineIntersection.cpp.

458 {
459 return LineCubicIntersections::HorizontalIntersect(*this, yIntercept, roots);
460}
static int HorizontalIntersect(const SkDCubic &c, double axisIntercept, double roots[3])

◆ hullIntersects() [1/4]

bool SkDCubic::hullIntersects ( const SkDConic c,
bool *  isLinear 
) const

Definition at line 215 of file SkPathOpsCubic.cpp.

215 {
216
217 return hullIntersects(conic.fPts, isLinear);
218}
AI float conic(float tolerance, const SkPoint pts[], float w, const VectorXform &vectorXform=VectorXform())
bool hullIntersects(const SkDCubic &c2, bool *isLinear) const
bool isLinear(int startIndex, int endIndex) const

◆ hullIntersects() [2/4]

bool SkDCubic::hullIntersects ( const SkDCubic c2,
bool *  isLinear 
) const

Definition at line 207 of file SkPathOpsCubic.cpp.

207 {
209}
static const int kPointCount

◆ hullIntersects() [3/4]

bool SkDCubic::hullIntersects ( const SkDPoint pts,
int  ptCount,
bool *  isLinear 
) const

Definition at line 158 of file SkPathOpsCubic.cpp.

158 {
159 bool linear = true;
160 char hullOrder[4];
161 int hullCount = convexHull(hullOrder);
162 int end1 = hullOrder[0];
163 int hullIndex = 0;
164 const SkDPoint* endPt[2];
165 endPt[0] = &fPts[end1];
166 do {
167 hullIndex = (hullIndex + 1) % hullCount;
168 int end2 = hullOrder[hullIndex];
169 endPt[1] = &fPts[end2];
170 double origX = endPt[0]->fX;
171 double origY = endPt[0]->fY;
172 double adj = endPt[1]->fX - origX;
173 double opp = endPt[1]->fY - origY;
174 int oddManMask = other_two(end1, end2);
175 int oddMan = end1 ^ oddManMask;
176 double sign = (fPts[oddMan].fY - origY) * adj - (fPts[oddMan].fX - origX) * opp;
177 int oddMan2 = end2 ^ oddManMask;
178 double sign2 = (fPts[oddMan2].fY - origY) * adj - (fPts[oddMan2].fX - origX) * opp;
179 if (sign * sign2 < 0) {
180 continue;
181 }
183 sign = sign2;
185 continue;
186 }
187 }
188 linear = false;
189 bool foundOutlier = false;
190 for (int n = 0; n < ptCount; ++n) {
191 double test = (pts[n].fY - origY) * adj - (pts[n].fX - origX) * opp;
192 if (test * sign > 0 && !precisely_zero(test)) {
193 foundOutlier = true;
194 break;
195 }
196 }
197 if (!foundOutlier) {
198 return false;
199 }
200 endPt[0] = endPt[1];
201 end1 = end2;
202 } while (hullIndex);
203 *isLinear = linear;
204 return true;
205}
bool precisely_zero(double x)
static int sign(SkScalar x)
Definition SkPath.cpp:2141
int convexHull(char order[kPointCount]) const
static sk_sp< SkShader > linear(sk_sp< SkShader > shader)

◆ hullIntersects() [4/4]

bool SkDCubic::hullIntersects ( const SkDQuad c2,
bool *  isLinear 
) const

Definition at line 211 of file SkPathOpsCubic.cpp.

211 {
212 return hullIntersects(quad.fPts, SkDQuad::kPointCount, isLinear);
213}
static const int kPointCount

◆ IsConic()

static bool SkDCubic::IsConic ( )
inlinestatic

Definition at line 53 of file SkPathOpsCubic.h.

53{ return false; }

◆ isLinear()

bool SkDCubic::isLinear ( int  startIndex,
int  endIndex 
) const

Definition at line 220 of file SkPathOpsCubic.cpp.

220 {
221 if (fPts[0].approximatelyDEqual(fPts[3])) {
222 return ((const SkDQuad *) this)->isLinear(0, 2);
223 }
224 SkLineParameters lineParameters;
225 lineParameters.cubicEndPoints(*this, startIndex, endIndex);
226 // FIXME: maybe it's possible to avoid this and compare non-normalized
227 lineParameters.normalize();
228 double tiniest = std::min(std::min(std::min(std::min(std::min(std::min(std::min(fPts[0].fX, fPts[0].fY),
229 fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY), fPts[3].fX), fPts[3].fY);
230 double largest = std::max(std::max(std::max(std::max(std::max(std::max(std::max(fPts[0].fX, fPts[0].fY),
231 fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY), fPts[3].fX), fPts[3].fY);
232 largest = std::max(largest, -tiniest);
233 double distance = lineParameters.controlPtDistance(*this, 1);
234 if (!approximately_zero_when_compared_to(distance, largest)) {
235 return false;
236 }
237 distance = lineParameters.controlPtDistance(*this, 2);
238 return approximately_zero_when_compared_to(distance, largest);
239}
bool approximately_zero_when_compared_to(double x, double y)
bool cubicEndPoints(const SkDCubic &pts)
double controlPtDistance(const SkDCubic &pts, int index) const

◆ maxIntersections()

static int SkDCubic::maxIntersections ( )
inlinestatic

Definition at line 96 of file SkPathOpsCubic.h.

96{ return kMaxIntersections; }
static const int kMaxIntersections

◆ monotonicInX()

bool SkDCubic::monotonicInX ( ) const

Definition at line 334 of file SkPathOpsCubic.cpp.

334 {
335 return precisely_between(fPts[0].fX, fPts[1].fX, fPts[3].fX)
336 && precisely_between(fPts[0].fX, fPts[2].fX, fPts[3].fX);
337}
bool precisely_between(double a, double b, double c)

◆ monotonicInY()

bool SkDCubic::monotonicInY ( ) const

Definition at line 339 of file SkPathOpsCubic.cpp.

339 {
340 return precisely_between(fPts[0].fY, fPts[1].fY, fPts[3].fY)
341 && precisely_between(fPts[0].fY, fPts[2].fY, fPts[3].fY);
342}

◆ operator[]() [1/2]

SkDPoint & SkDCubic::operator[] ( int  n)
inline

Definition at line 56 of file SkPathOpsCubic.h.

56{ SkASSERT(n >= 0 && n < kPointCount); return fPts[n]; }
#define SkASSERT(cond)
Definition SkAssert.h:116

◆ operator[]() [2/2]

const SkDPoint & SkDCubic::operator[] ( int  n) const
inline

Definition at line 55 of file SkPathOpsCubic.h.

55{ SkASSERT(n >= 0 && n < kPointCount); return fPts[n]; }

◆ otherPts()

void SkDCubic::otherPts ( int  index,
const SkDPoint o1Pts[kPointCount - 1] 
) const

Definition at line 344 of file SkPathOpsCubic.cpp.

344 {
345 int offset = (int) !SkToBool(index);
346 o1Pts[0] = &fPts[offset];
347 o1Pts[1] = &fPts[++offset];
348 o1Pts[2] = &fPts[++offset];
349}
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35
Point offset

◆ pointCount()

static int SkDCubic::pointCount ( )
inlinestatic

Definition at line 100 of file SkPathOpsCubic.h.

100{ return kPointCount; }

◆ pointLast()

static int SkDCubic::pointLast ( )
inlinestatic

Definition at line 101 of file SkPathOpsCubic.h.

101{ return kPointLast; }
static const int kPointLast

◆ ptAtT()

SkDPoint SkDCubic::ptAtT ( double  t) const

Definition at line 591 of file SkPathOpsCubic.cpp.

591 {
592 if (0 == t) {
593 return fPts[0];
594 }
595 if (1 == t) {
596 return fPts[3];
597 }
598 double one_t = 1 - t;
599 double one_t2 = one_t * one_t;
600 double a = one_t2 * one_t;
601 double b = 3 * one_t2 * t;
602 double t2 = t * t;
603 double c = 3 * one_t * t2;
604 double d = t2 * t;
605 SkDPoint result = {a * fPts[0].fX + b * fPts[1].fX + c * fPts[2].fX + d * fPts[3].fX,
606 a * fPts[0].fY + b * fPts[1].fY + c * fPts[2].fY + d * fPts[3].fY};
607 return result;
608}

◆ RootsReal()

int SkDCubic::RootsReal ( double  A,
double  B,
double  C,
double  D,
double  t[3] 
)
static

Definition at line 412 of file SkPathOpsCubic.cpp.

412 {
413#ifdef SK_DEBUG
414 #if ONE_OFF_DEBUG && ONE_OFF_DEBUG_MATHEMATICA
415 // create a string mathematica understands
416 // GDB set print repe 15 # if repeated digits is a bother
417 // set print elements 400 # if line doesn't fit
418 char str[1024];
419 sk_bzero(str, sizeof(str));
420 snprintf(str, sizeof(str), "Solve[%1.19g x^3 + %1.19g x^2 + %1.19g x + %1.19g == 0, x]",
421 A, B, C, D);
422 SkPathOpsDebug::MathematicaIze(str, sizeof(str));
423 SkDebugf("%s\n", str);
424 #endif
425#endif
429 && approximately_zero_when_compared_to(A, D)) { // we're just a quadratic
430 return SkDQuad::RootsReal(B, C, D, s);
431 }
434 && approximately_zero_when_compared_to(D, C)) { // 0 is one root
435 int num = SkDQuad::RootsReal(A, B, C, s);
436 for (int i = 0; i < num; ++i) {
437 if (approximately_zero(s[i])) {
438 return num;
439 }
440 }
441 s[num++] = 0;
442 return num;
443 }
444 if (approximately_zero(A + B + C + D)) { // 1 is one root
445 int num = SkDQuad::RootsReal(A, A + B, -D, s);
446 for (int i = 0; i < num; ++i) {
447 if (AlmostDequalUlps(s[i], 1)) {
448 return num;
449 }
450 }
451 s[num++] = 1;
452 return num;
453 }
454 double a, b, c;
455 {
456 double invA = 1 / A;
457 a = B * invA;
458 b = C * invA;
459 c = D * invA;
460 }
461 double a2 = a * a;
462 double Q = (a2 - b * 3) / 9;
463 double R = (2 * a2 * a - 9 * a * b + 27 * c) / 54;
464 double R2 = R * R;
465 double Q3 = Q * Q * Q;
466 double R2MinusQ3 = R2 - Q3;
467 double adiv3 = a / 3;
468 double r;
469 double* roots = s;
470 if (R2MinusQ3 < 0) { // we have 3 real roots
471 // the divide/root can, due to finite precisions, be slightly outside of -1...1
472 double theta = acos(SkTPin(R / sqrt(Q3), -1., 1.));
473 double neg2RootQ = -2 * sqrt(Q);
474
475 r = neg2RootQ * cos(theta / 3) - adiv3;
476 *roots++ = r;
477
478 r = neg2RootQ * cos((theta + 2 * PI) / 3) - adiv3;
479 if (!AlmostDequalUlps(s[0], r)) {
480 *roots++ = r;
481 }
482 r = neg2RootQ * cos((theta - 2 * PI) / 3) - adiv3;
483 if (!AlmostDequalUlps(s[0], r) && (roots - s == 1 || !AlmostDequalUlps(s[1], r))) {
484 *roots++ = r;
485 }
486 } else { // we have 1 real root
487 double sqrtR2MinusQ3 = sqrt(R2MinusQ3);
488 A = fabs(R) + sqrtR2MinusQ3;
489 A = std::cbrt(A); // cube root
490 if (R > 0) {
491 A = -A;
492 }
493 if (A != 0) {
494 A += Q / A;
495 }
496 r = A - adiv3;
497 *roots++ = r;
498 if (AlmostDequalUlps((double) R2, (double) Q3)) {
499 r = -A / 2 - adiv3;
500 if (!AlmostDequalUlps(s[0], r)) {
501 *roots++ = r;
502 }
503 }
504 }
505 return static_cast<int>(roots - s);
506}
#define PI
bool AlmostDequalUlps(float a, float b)
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
Definition SkTPin.h:19
static void MathematicaIze(char *str, size_t bufferSize)
struct MyStruct s
#define R(r)
SIN Vec< N, float > sqrt(const Vec< N, float > &x)
Definition SkVx.h:706
static int RootsReal(double A, double B, double C, double t[2])

◆ RootsValidT()

int SkDCubic::RootsValidT ( const double  A,
const double  B,
const double  C,
double  D,
double  s[3] 
)
static

Definition at line 382 of file SkPathOpsCubic.cpp.

382 {
383 double s[3];
384 int realRoots = RootsReal(A, B, C, D, s);
385 int foundRoots = SkDQuad::AddValidTs(s, realRoots, t);
386 for (int index = 0; index < realRoots; ++index) {
387 double tValue = s[index];
388 if (!approximately_one_or_less(tValue) && between(1, tValue, 1.00005)) {
389 for (int idx2 = 0; idx2 < foundRoots; ++idx2) {
390 if (approximately_equal(t[idx2], 1)) {
391 goto nextRoot;
392 }
393 }
394 SkASSERT(foundRoots < 3);
395 t[foundRoots++] = 1;
396 } else if (!approximately_zero_or_more(tValue) && between(-0.00005, tValue, 0)) {
397 for (int idx2 = 0; idx2 < foundRoots; ++idx2) {
398 if (approximately_equal(t[idx2], 0)) {
399 goto nextRoot;
400 }
401 }
402 SkASSERT(foundRoots < 3);
403 t[foundRoots++] = 0;
404 }
405nextRoot:
406 ;
407 }
408 return foundRoots;
409}
bool approximately_one_or_less(double x)
bool approximately_zero_or_more(double x)
static int RootsReal(double A, double B, double C, double D, double t[3])
static int AddValidTs(double s[], int realRoots, double *t)

◆ searchRoots()

int SkDCubic::searchRoots ( double  extremes[6],
int  extrema,
double  axisIntercept,
SearchAxis  xAxis,
double *  validRoots 
) const

Definition at line 351 of file SkPathOpsCubic.cpp.

352 {
353 extrema += findInflections(&extremeTs[extrema]);
354 extremeTs[extrema++] = 0;
355 extremeTs[extrema] = 1;
356 SkASSERT(extrema < 6);
357 SkTQSort(extremeTs, extremeTs + extrema + 1);
358 int validCount = 0;
359 for (int index = 0; index < extrema; ) {
360 double min = extremeTs[index];
361 double max = extremeTs[++index];
362 if (min == max) {
363 continue;
364 }
365 double newT = binarySearch(min, max, axisIntercept, xAxis);
366 if (newT >= 0) {
367 if (validCount >= 3) {
368 return 0;
369 }
370 validRoots[validCount++] = newT;
371 }
372 }
373 return validCount;
374}
void SkTQSort(T *begin, T *end, const C &lessThan)
Definition SkTSort.h:194
double binarySearch(double min, double max, double axisIntercept, SearchAxis xAxis) const
int findInflections(double tValues[2]) const

◆ set()

const SkDCubic & SkDCubic::set ( const SkPoint pts   SkDEBUGPARAMS(SkOpGlobalState *state=nullptr)[kPointCount])
inline

Definition at line 122 of file SkPathOpsCubic.h.

123 {
124 fPts[0] = pts[0];
125 fPts[1] = pts[1];
126 fPts[2] = pts[2];
127 fPts[3] = pts[3];
128 SkDEBUGCODE(fDebugGlobalState = state);
129 return *this;
130 }
AtkStateType state

◆ subDivide() [1/3]

void SkDCubic::subDivide ( const SkDPoint a,
const SkDPoint d,
double  t1,
double  t2,
SkDPoint  p[2] 
) const

Definition at line 696 of file SkPathOpsCubic.cpp.

697 {
698 SkASSERT(t1 != t2);
699 // this approach assumes that the control points computed directly are accurate enough
700 SkDCubic sub = subDivide(t1, t2);
701 dst[0] = sub[1] + (a - sub[0]);
702 dst[1] = sub[2] + (d - sub[3]);
703 if (t1 == 0 || t2 == 0) {
704 align(0, 1, t1 == 0 ? &dst[0] : &dst[1]);
705 }
706 if (t1 == 1 || t2 == 1) {
707 align(3, 2, t1 == 1 ? &dst[0] : &dst[1]);
708 }
709 if (AlmostBequalUlps(dst[0].fX, a.fX)) {
710 dst[0].fX = a.fX;
711 }
712 if (AlmostBequalUlps(dst[0].fY, a.fY)) {
713 dst[0].fY = a.fY;
714 }
715 if (AlmostBequalUlps(dst[1].fX, d.fX)) {
716 dst[1].fX = d.fX;
717 }
718 if (AlmostBequalUlps(dst[1].fY, d.fY)) {
719 dst[1].fY = d.fY;
720 }
721}
bool AlmostBequalUlps(float a, float b)
void align(int endIndex, int ctrlIndex, SkDPoint *dstPt) const
SkDCubic subDivide(double t1, double t2) const

◆ SubDivide() [1/2]

static SkDCubic SkDCubic::SubDivide ( const SkPoint  a[kPointCount],
double  t1,
double  t2 
)
inlinestatic

Definition at line 135 of file SkPathOpsCubic.h.

135 {
137 return cubic.set(a).subDivide(t1, t2);
138 }

◆ SubDivide() [2/2]

static void SkDCubic::SubDivide ( const SkPoint  pts[kPointCount],
const SkDPoint a,
const SkDPoint d,
double  t1,
double  t2,
SkDPoint  p[2] 
)
inlinestatic

Definition at line 142 of file SkPathOpsCubic.h.

143 {
145 cubic.set(pts).subDivide(a, d, t1, t2, p);
146 }

◆ subDivide() [2/3]

SkDCubic SkDCubic::subDivide ( double  t1,
double  t2 
) const

Definition at line 666 of file SkPathOpsCubic.cpp.

666 {
667 if (t1 == 0 || t2 == 1) {
668 if (t1 == 0 && t2 == 1) {
669 return *this;
670 }
671 SkDCubicPair pair = chopAt(t1 == 0 ? t2 : t1);
672 SkDCubic dst = t1 == 0 ? pair.first() : pair.second();
673 return dst;
674 }
676 double ax = dst[0].fX = interp_cubic_coords(&fPts[0].fX, t1);
677 double ay = dst[0].fY = interp_cubic_coords(&fPts[0].fY, t1);
678 double ex = interp_cubic_coords(&fPts[0].fX, (t1*2+t2)/3);
679 double ey = interp_cubic_coords(&fPts[0].fY, (t1*2+t2)/3);
680 double fx = interp_cubic_coords(&fPts[0].fX, (t1+t2*2)/3);
681 double fy = interp_cubic_coords(&fPts[0].fY, (t1+t2*2)/3);
682 double dx = dst[3].fX = interp_cubic_coords(&fPts[0].fX, t2);
683 double dy = dst[3].fY = interp_cubic_coords(&fPts[0].fY, t2);
684 double mx = ex * 27 - ax * 8 - dx;
685 double my = ey * 27 - ay * 8 - dy;
686 double nx = fx * 27 - ax - dx * 8;
687 double ny = fy * 27 - ay - dy * 8;
688 /* bx = */ dst[1].fX = (mx * 2 - nx) / 18;
689 /* by = */ dst[1].fY = (my * 2 - ny) / 18;
690 /* cx = */ dst[2].fX = (nx * 2 - mx) / 18;
691 /* cy = */ dst[2].fY = (ny * 2 - my) / 18;
692 // FIXME: call align() ?
693 return dst;
694}
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
Definition SkRecords.h:208
SkDCubic second() const
SkDCubic first() const
SkDCubicPair chopAt(double t) const

◆ subDivide() [3/3]

void SkDCubic::subDivide ( double  t1,
double  t2,
SkDCubic c 
) const
inline

Definition at line 133 of file SkPathOpsCubic.h.

133{ *c = this->subDivide(t1, t2); }

◆ toFloatPoints()

bool SkDCubic::toFloatPoints ( SkPoint pts) const

Definition at line 723 of file SkPathOpsCubic.cpp.

723 {
724 const double* dCubic = &fPts[0].fX;
725 SkScalar* cubic = &pts[0].fX;
726 for (int index = 0; index < kPointCount * 2; ++index) {
727 cubic[index] = SkDoubleToScalar(dCubic[index]);
728 if (SkScalarAbs(cubic[index]) < FLT_EPSILON_ORDERABLE_ERR) {
729 cubic[index] = 0;
730 }
731 }
732 return SkIsFinite(&pts->fX, kPointCount * 2);
733}
static bool SkIsFinite(T x, Pack... values)
const double FLT_EPSILON_ORDERABLE_ERR
#define SkDoubleToScalar(x)
Definition SkScalar.h:64
#define SkScalarAbs(x)
Definition SkScalar.h:39
float fX
x-axis value

◆ top()

double SkDCubic::top ( const SkDCubic dCurve,
double  startT,
double  endT,
SkDPoint topPt 
) const

Definition at line 735 of file SkPathOpsCubic.cpp.

735 {
736 double extremeTs[2];
737 double topT = -1;
738 int roots = SkDCubic::FindExtrema(&fPts[0].fY, extremeTs);
739 for (int index = 0; index < roots; ++index) {
740 double t = startT + (endT - startT) * extremeTs[index];
741 SkDPoint mid = dCurve.ptAtT(t);
742 if (topPt->fY > mid.fY || (topPt->fY == mid.fY && topPt->fX > mid.fX)) {
743 topT = t;
744 *topPt = mid;
745 }
746 }
747 return topT;
748}
static int FindExtrema(const double src[], double tValue[2])

◆ toQuad()

SkDQuad SkDCubic::toQuad ( ) const

Definition at line 36 of file SkDCubicToQuads.cpp.

36 {
37 SkDQuad quad;
38 quad[0] = fPts[0];
39 const SkDPoint fromC1 = {(3 * fPts[1].fX - fPts[0].fX) / 2, (3 * fPts[1].fY - fPts[0].fY) / 2};
40 const SkDPoint fromC2 = {(3 * fPts[2].fX - fPts[3].fX) / 2, (3 * fPts[2].fY - fPts[3].fY) / 2};
41 quad[1].fX = (fromC1.fX + fromC2.fX) / 2;
42 quad[1].fY = (fromC1.fY + fromC2.fY) / 2;
43 quad[2] = fPts[3];
44 return quad;
45}

◆ verticalIntersect()

int SkDCubic::verticalIntersect ( double  xIntercept,
double  roots[3] 
) const

Return the number of valid roots (0 < root < 1) for this cubic intersecting the specified vertical line.

Definition at line 462 of file SkDCubicLineIntersection.cpp.

462 {
463 return LineCubicIntersections::VerticalIntersect(*this, xIntercept, roots);
464}
static int VerticalIntersect(const SkDCubic &c, double axisIntercept, double roots[3])

Member Data Documentation

◆ fPts

SkDPoint SkDCubic::fPts[kPointCount]

Definition at line 152 of file SkPathOpsCubic.h.

◆ gPrecisionUnit

const int SkDCubic::gPrecisionUnit = 256
static

Definition at line 151 of file SkPathOpsCubic.h.

◆ kMaxIntersections

const int SkDCubic::kMaxIntersections = 9
static

Definition at line 32 of file SkPathOpsCubic.h.

◆ kPointCount

const int SkDCubic::kPointCount = 4
static

Definition at line 30 of file SkPathOpsCubic.h.

◆ kPointLast

const int SkDCubic::kPointLast = kPointCount - 1
static

Definition at line 31 of file SkPathOpsCubic.h.


The documentation for this struct was generated from the following files: