Flutter Engine
The Flutter Engine
Classes | Enumerations | Functions
SkGeometry.h File Reference
#include "include/core/SkPoint.h"
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkFloatingPoint.h"
#include "src/base/SkVx.h"
#include <cstring>
#include "include/private/base/SkTemplates.h"

Go to the source code of this file.

Classes

struct  SkConic
 
class  SkAutoConicToQuads
 

Enumerations

enum class  SkCubicType {
  kSerpentine , kLoop , kLocalCusp , kCuspAtInfinity ,
  kQuadratic , kLineOrPoint
}
 
enum  SkRotationDirection { kCW_SkRotationDirection , kCCW_SkRotationDirection }
 

Functions

static skvx::float2 from_point (const SkPoint &point)
 
static SkPoint to_point (const skvx::float2 &x)
 
static skvx::float2 times_2 (const skvx::float2 &value)
 
int SkFindUnitQuadRoots (SkScalar A, SkScalar B, SkScalar C, SkScalar roots[2])
 
float SkMeasureAngleBetweenVectors (SkVector, SkVector)
 
SkVector SkFindBisector (SkVector, SkVector)
 
SkPoint SkEvalQuadAt (const SkPoint src[3], SkScalar t)
 
SkPoint SkEvalQuadTangentAt (const SkPoint src[3], SkScalar t)
 
void SkEvalQuadAt (const SkPoint src[3], SkScalar t, SkPoint *pt, SkVector *tangent=nullptr)
 
void SkChopQuadAt (const SkPoint src[3], SkPoint dst[5], SkScalar t)
 
void SkChopQuadAtHalf (const SkPoint src[3], SkPoint dst[5])
 
float SkMeasureQuadRotation (const SkPoint pts[3])
 
float SkFindQuadMidTangent (const SkPoint src[3])
 
void SkChopQuadAtMidTangent (const SkPoint src[3], SkPoint dst[5])
 
int SkFindQuadExtrema (SkScalar a, SkScalar b, SkScalar c, SkScalar tValues[1])
 
int SkChopQuadAtYExtrema (const SkPoint src[3], SkPoint dst[5])
 
int SkChopQuadAtXExtrema (const SkPoint src[3], SkPoint dst[5])
 
SkScalar SkFindQuadMaxCurvature (const SkPoint src[3])
 
int SkChopQuadAtMaxCurvature (const SkPoint src[3], SkPoint dst[5])
 
void SkConvertQuadToCubic (const SkPoint src[3], SkPoint dst[4])
 
void SkEvalCubicAt (const SkPoint src[4], SkScalar t, SkPoint *locOrNull, SkVector *tangentOrNull, SkVector *curvatureOrNull)
 
void SkChopCubicAt (const SkPoint src[4], SkPoint dst[7], SkScalar t)
 
void SkChopCubicAt (const SkPoint src[4], SkPoint dst[10], float t0, float t1)
 
void SkChopCubicAt (const SkPoint src[4], SkPoint dst[], const SkScalar t[], int t_count)
 
void SkChopCubicAtHalf (const SkPoint src[4], SkPoint dst[7])
 
float SkMeasureNonInflectCubicRotation (const SkPoint[4])
 
float SkFindCubicMidTangent (const SkPoint src[4])
 
void SkChopCubicAtMidTangent (const SkPoint src[4], SkPoint dst[7])
 
int SkFindCubicExtrema (SkScalar a, SkScalar b, SkScalar c, SkScalar d, SkScalar tValues[2])
 
int SkChopCubicAtYExtrema (const SkPoint src[4], SkPoint dst[10])
 
int SkChopCubicAtXExtrema (const SkPoint src[4], SkPoint dst[10])
 
int SkFindCubicInflections (const SkPoint src[4], SkScalar tValues[2])
 
int SkChopCubicAtInflections (const SkPoint src[4], SkPoint dst[10])
 
int SkFindCubicMaxCurvature (const SkPoint src[4], SkScalar tValues[3])
 
int SkChopCubicAtMaxCurvature (const SkPoint src[4], SkPoint dst[13], SkScalar tValues[3]=nullptr)
 
SkScalar SkFindCubicCusp (const SkPoint src[4])
 
bool SkChopMonoCubicAtX (const SkPoint src[4], SkScalar x, SkPoint dst[7])
 
bool SkChopMonoCubicAtY (const SkPoint src[4], SkScalar y, SkPoint dst[7])
 
static bool SkCubicIsDegenerate (SkCubicType type)
 
static const char * SkCubicTypeName (SkCubicType type)
 
SkCubicType SkClassifyCubic (const SkPoint p[4], double t[2]=nullptr, double s[2]=nullptr, double d[4]=nullptr)
 

Enumeration Type Documentation

◆ SkCubicType

enum class SkCubicType
strong
Enumerator
kSerpentine 
kLoop 
kLocalCusp 
kCuspAtInfinity 
kQuadratic 
kLineOrPoint 

Definition at line 264 of file SkGeometry.h.

264 {
266 kLoop,
267 kLocalCusp, // Cusp at a non-infinite parameter value with an inflection at t=infinity.
268 kCuspAtInfinity, // Cusp with a cusp at t=infinity and a local inflection.
271};
const SkPoint kLoop[4]

◆ SkRotationDirection

Enumerator
kCW_SkRotationDirection 
kCCW_SkRotationDirection 

Definition at line 321 of file SkGeometry.h.

321 {
324};
@ kCW_SkRotationDirection
Definition: SkGeometry.h:322
@ kCCW_SkRotationDirection
Definition: SkGeometry.h:323

Function Documentation

◆ from_point()

static skvx::float2 from_point ( const SkPoint point)
inlinestatic

Definition at line 22 of file SkGeometry.h.

22 {
23 return skvx::float2::Load(&point);
24}
static SKVX_ALWAYS_INLINE Vec Load(const void *ptr)
Definition: SkVx.h:109

◆ SkChopCubicAt() [1/3]

void SkChopCubicAt ( const SkPoint  src[4],
SkPoint  dst[10],
float  t0,
float  t1 
)

Given a src cubic bezier, chop it at the specified t0 and t1 values, where 0 <= t0 <= t1 <= 1, and return the three new cubics in dst: dst[0..3], dst[3..6], and dst[6..9]

Definition at line 504 of file SkGeometry.cpp.

504 {
505 SkASSERT(0 <= t0 && t0 <= t1 && t1 <= 1);
506
507 if (t1 == 1) {
508 SkChopCubicAt(src, dst, t0);
509 dst[7] = dst[8] = dst[9] = src[3];
510 return;
511 }
512
513 // Perform both chops in parallel using 4-lane SIMD.
514 float4 p00, p11, p22, p33, T;
515 p00.lo = p00.hi = sk_bit_cast<float2>(src[0]);
516 p11.lo = p11.hi = sk_bit_cast<float2>(src[1]);
517 p22.lo = p22.hi = sk_bit_cast<float2>(src[2]);
518 p33.lo = p33.hi = sk_bit_cast<float2>(src[3]);
519 T.lo = t0;
520 T.hi = t1;
521
522 float4 ab = unchecked_mix(p00, p11, T);
523 float4 bc = unchecked_mix(p11, p22, T);
524 float4 cd = unchecked_mix(p22, p33, T);
525 float4 abc = unchecked_mix(ab, bc, T);
526 float4 bcd = unchecked_mix(bc, cd, T);
527 float4 abcd = unchecked_mix(abc, bcd, T);
528 float4 middle = unchecked_mix(abc, bcd, skvx::shuffle<2,3,0,1>(T));
529
530 dst[0] = sk_bit_cast<SkPoint>(p00.lo);
531 dst[1] = sk_bit_cast<SkPoint>(ab.lo);
532 dst[2] = sk_bit_cast<SkPoint>(abc.lo);
533 dst[3] = sk_bit_cast<SkPoint>(abcd.lo);
534 middle.store(dst + 4);
535 dst[6] = sk_bit_cast<SkPoint>(abcd.hi);
536 dst[7] = sk_bit_cast<SkPoint>(bcd.hi);
537 dst[8] = sk_bit_cast<SkPoint>(cd.hi);
538 dst[9] = sk_bit_cast<SkPoint>(p33.hi);
539}
#define SkASSERT(cond)
Definition: SkAssert.h:116
static skvx::Vec< N, T > unchecked_mix(const skvx::Vec< N, T > &a, const skvx::Vec< N, T > &b, const skvx::Vec< N, T > &t)
Definition: SkGeometry.cpp:468
void SkChopCubicAt(const SkPoint src[4], SkPoint dst[7], SkScalar t)
Definition: SkGeometry.cpp:473
Definition: ab.py:1
dst
Definition: cp.py:12
#define T
Definition: precompiler.cc:65
Definition: SkVx.h:83
SKVX_ALWAYS_INLINE void store(void *ptr) const
Definition: SkVx.h:112
Vec< N/2, T > hi
Definition: SkVx.h:117
Vec< N/2, T > lo
Definition: SkVx.h:117

◆ SkChopCubicAt() [2/3]

void SkChopCubicAt ( const SkPoint  src[4],
SkPoint  dst[7],
SkScalar  t 
)

Given a src cubic bezier, chop it at the specified t value, where 0 <= t <= 1, and return the two new cubics in dst: dst[0..3] and dst[3..6]

Definition at line 473 of file SkGeometry.cpp.

473 {
474 SkASSERT(0 <= t && t <= 1);
475
476 if (t == 1) {
477 memcpy(dst, src, sizeof(SkPoint) * 4);
478 dst[4] = dst[5] = dst[6] = src[3];
479 return;
480 }
481
482 float2 p0 = sk_bit_cast<float2>(src[0]);
483 float2 p1 = sk_bit_cast<float2>(src[1]);
484 float2 p2 = sk_bit_cast<float2>(src[2]);
485 float2 p3 = sk_bit_cast<float2>(src[3]);
486 float2 T = t;
487
488 float2 ab = unchecked_mix(p0, p1, T);
489 float2 bc = unchecked_mix(p1, p2, T);
490 float2 cd = unchecked_mix(p2, p3, T);
491 float2 abc = unchecked_mix(ab, bc, T);
492 float2 bcd = unchecked_mix(bc, cd, T);
493 float2 abcd = unchecked_mix(abc, bcd, T);
494
495 dst[0] = sk_bit_cast<SkPoint>(p0);
496 dst[1] = sk_bit_cast<SkPoint>(ab);
497 dst[2] = sk_bit_cast<SkPoint>(abc);
498 dst[3] = sk_bit_cast<SkPoint>(abcd);
499 dst[4] = sk_bit_cast<SkPoint>(bcd);
500 dst[5] = sk_bit_cast<SkPoint>(cd);
501 dst[6] = sk_bit_cast<SkPoint>(p3);
502}

◆ SkChopCubicAt() [3/3]

void SkChopCubicAt ( const SkPoint  src[4],
SkPoint  dst[],
const SkScalar  t[],
int  t_count 
)

Given a src cubic bezier, chop it at the specified t values, where 0 <= t0 <= t1 <= ... <= 1, and return the new cubics in dst: dst[0..3],dst[3..6],...,dst[3*t_count..3*(t_count+1)]

Definition at line 541 of file SkGeometry.cpp.

542 {
543 SkASSERT(std::all_of(tValues, tValues + tCount, [](SkScalar t) { return t >= 0 && t <= 1; }));
544 SkASSERT(std::is_sorted(tValues, tValues + tCount));
545
546 if (dst) {
547 if (tCount == 0) { // nothing to chop
548 memcpy(dst, src, 4*sizeof(SkPoint));
549 } else {
550 int i = 0;
551 for (; i < tCount - 1; i += 2) {
552 // Do two chops at once.
553 float2 tt = float2::Load(tValues + i);
554 if (i != 0) {
555 float lastT = tValues[i - 1];
556 tt = skvx::pin((tt - lastT) / (1 - lastT), float2(0), float2(1));
557 }
558 SkChopCubicAt(src, dst, tt[0], tt[1]);
559 src = dst = dst + 6;
560 }
561 if (i < tCount) {
562 // Chop the final cubic if there was an odd number of chops.
563 SkASSERT(i + 1 == tCount);
564 float t = tValues[i];
565 if (i != 0) {
566 float lastT = tValues[i - 1];
567 t = SkTPin(sk_ieee_float_divide(t - lastT, 1 - lastT), 0.f, 1.f);
568 }
569 SkChopCubicAt(src, dst, t);
570 }
571 }
572 }
573}
static constexpr float sk_ieee_float_divide(float numer, float denom)
skvx::float2 float2
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
Definition: SkTPin.h:19
float SkScalar
Definition: extension.cpp:12
SINT Vec< N, T > pin(const Vec< N, T > &x, const Vec< N, T > &lo, const Vec< N, T > &hi)
Definition: SkVx.h:655

◆ SkChopCubicAtHalf()

void SkChopCubicAtHalf ( const SkPoint  src[4],
SkPoint  dst[7] 
)

Given a src cubic bezier, chop it at the specified t == 1/2, The new cubics are returned in dst[0..3] and dst[3..6]

Definition at line 575 of file SkGeometry.cpp.

575 {
576 SkChopCubicAt(src, dst, 0.5f);
577}

◆ SkChopCubicAtInflections()

int SkChopCubicAtInflections ( const SkPoint  src[4],
SkPoint  dst[10] 
)

Return 1 for no chop, 2 for having chopped the cubic at a single inflection point, 3 for having chopped at 2 inflection points. dst will hold the resulting 1, 2, or 3 cubics.

Definition at line 755 of file SkGeometry.cpp.

755 {
756 SkScalar tValues[2];
757 int count = SkFindCubicInflections(src, tValues);
758
759 if (dst) {
760 if (count == 0) {
761 memcpy(dst, src, 4 * sizeof(SkPoint));
762 } else {
763 SkChopCubicAt(src, dst, tValues, count);
764 }
765 }
766 return count + 1;
767}
int count
Definition: FontMgrTest.cpp:50
int SkFindCubicInflections(const SkPoint src[4], SkScalar tValues[2])
Definition: SkGeometry.cpp:741

◆ SkChopCubicAtMaxCurvature()

int SkChopCubicAtMaxCurvature ( const SkPoint  src[4],
SkPoint  dst[13],
SkScalar  tValues[3] = nullptr 
)

Definition at line 1060 of file SkGeometry.cpp.

1061 {
1062 SkScalar t_storage[3];
1063
1064 if (tValues == nullptr) {
1065 tValues = t_storage;
1066 }
1067
1068 SkScalar roots[3];
1069 int rootCount = SkFindCubicMaxCurvature(src, roots);
1070
1071 // Throw out values not inside 0..1.
1072 int count = 0;
1073 for (int i = 0; i < rootCount; ++i) {
1074 if (0 < roots[i] && roots[i] < 1) {
1075 tValues[count++] = roots[i];
1076 }
1077 }
1078
1079 if (dst) {
1080 if (count == 0) {
1081 memcpy(dst, src, 4 * sizeof(SkPoint));
1082 } else {
1083 SkChopCubicAt(src, dst, tValues, count);
1084 }
1085 }
1086 return count + 1;
1087}
int SkFindCubicMaxCurvature(const SkPoint src[4], SkScalar tValues[3])

◆ SkChopCubicAtMidTangent()

void SkChopCubicAtMidTangent ( const SkPoint  src[4],
SkPoint  dst[7] 
)
inline

Given a src cubic bezier, chop it at the tangent whose angle is halfway between the tangents at p0 and p3. The new cubics are returned in dst[0..3] and dst[3..6].

NOTE: 0- and 360-degree flat lines don't have single points of midtangent. (tangent == midtangent at every point on these curves except the cusp points.) If this is the case then we simply chop at a point which guarantees neither side rotates more than 180 degrees.

Definition at line 195 of file SkGeometry.h.

195 {
197}
void SkChopCubicAt(const SkPoint src[4], SkPoint dst[7], SkScalar t)
Definition: SkGeometry.cpp:473
float SkFindCubicMidTangent(const SkPoint src[4])
Definition: SkGeometry.cpp:620

◆ SkChopCubicAtXExtrema()

int SkChopCubicAtXExtrema ( const SkPoint  src[4],
SkPoint  dst[10] 
)

Definition at line 714 of file SkGeometry.cpp.

714 {
715 SkScalar tValues[2];
716 int roots = SkFindCubicExtrema(src[0].fX, src[1].fX, src[2].fX,
717 src[3].fX, tValues);
718
719 SkChopCubicAt(src, dst, tValues, roots);
720 if (dst && roots > 0) {
721 // we do some cleanup to ensure our Y extrema are flat
723 if (roots == 2) {
725 }
726 }
727 return roots;
728}
static void flatten_double_cubic_extrema(SkScalar coords[14])
Definition: SkGeometry.cpp:686
int SkFindCubicExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar d, SkScalar tValues[2])
Definition: SkGeometry.cpp:454

◆ SkChopCubicAtYExtrema()

int SkChopCubicAtYExtrema ( const SkPoint  src[4],
SkPoint  dst[10] 
)

Given 4 points on a cubic bezier, chop it into 1, 2, 3 beziers such that the resulting beziers are monotonic in Y. This is called by the scan converter. Depending on what is returned, dst[] is treated as follows 0 dst[0..3] is the original cubic 1 dst[0..3] and dst[3..6] are the two new cubics 2 dst[0..3], dst[3..6], dst[6..9] are the three new cubics If dst == null, it is ignored and only the count is returned.

Given 4 points on a cubic bezier, chop it into 1, 2, 3 beziers such that the resulting beziers are monotonic in Y. This is called by the scan converter. Depending on what is returned, dst[] is treated as follows: 0 dst[0..3] is the original cubic 1 dst[0..3] and dst[3..6] are the two new cubics 2 dst[0..3], dst[3..6], dst[6..9] are the three new cubics If dst == null, it is ignored and only the count is returned.

Definition at line 698 of file SkGeometry.cpp.

698 {
699 SkScalar tValues[2];
700 int roots = SkFindCubicExtrema(src[0].fY, src[1].fY, src[2].fY,
701 src[3].fY, tValues);
702
703 SkChopCubicAt(src, dst, tValues, roots);
704 if (dst && roots > 0) {
705 // we do some cleanup to ensure our Y extrema are flat
707 if (roots == 2) {
709 }
710 }
711 return roots;
712}

◆ SkChopMonoCubicAtX()

bool SkChopMonoCubicAtX ( const SkPoint  src[4],
SkScalar  x,
SkPoint  dst[7] 
)

Given a monotonically increasing or decreasing cubic bezier src, chop it where the X value is the specified value. The returned cubics will be in dst, sharing the middle point. That is, the first cubic is dst[0..3] and the second dst[3..6].

If the cubic provided is not monotone, it will be chopped at the first time the curve has the specified X value.

If the cubic never reaches the specified value, the function returns false.

Definition at line 1204 of file SkGeometry.cpp.

1204 {
1205 double coefficients[8] = {src[0].fX, src[0].fY, src[1].fX, src[1].fY,
1206 src[2].fX, src[2].fY, src[3].fX, src[3].fY};
1207 double solution = 0;
1208 if (first_axis_intersection(coefficients, false, x, &solution)) {
1209 double cubicPair[14];
1210 SkBezierCubic::Subdivide(coefficients, solution, cubicPair);
1211 for (int i = 0; i < 7; i ++) {
1212 dst[i].fX = sk_double_to_float(cubicPair[i*2]);
1213 dst[i].fY = sk_double_to_float(cubicPair[i*2 + 1]);
1214 }
1215 return true;
1216 }
1217 return false;
1218}
static constexpr float sk_double_to_float(double x)
static bool first_axis_intersection(const double coefficients[8], bool yDirection, double axisIntercept, double *solution)
static void Subdivide(const double curve[8], double t, double twoCurves[14])
double x

◆ SkChopMonoCubicAtY()

bool SkChopMonoCubicAtY ( const SkPoint  src[4],
SkScalar  y,
SkPoint  dst[7] 
)

Given a monotonically increasing or decreasing cubic bezier src, chop it where the Y value is the specified value. The returned cubics will be in dst, sharing the middle point. That is, the first cubic is dst[0..3] and the second dst[3..6].

If the cubic provided is not monotone, it will be chopped at the first time the curve has the specified Y value.

If the cubic never reaches the specified value, the function returns false.

Definition at line 1188 of file SkGeometry.cpp.

1188 {
1189 double coefficients[8] = {src[0].fX, src[0].fY, src[1].fX, src[1].fY,
1190 src[2].fX, src[2].fY, src[3].fX, src[3].fY};
1191 double solution = 0;
1192 if (first_axis_intersection(coefficients, true, y, &solution)) {
1193 double cubicPair[14];
1194 SkBezierCubic::Subdivide(coefficients, solution, cubicPair);
1195 for (int i = 0; i < 7; i ++) {
1196 dst[i].fX = sk_double_to_float(cubicPair[i*2]);
1197 dst[i].fY = sk_double_to_float(cubicPair[i*2 + 1]);
1198 }
1199 return true;
1200 }
1201 return false;
1202}
double y

◆ SkChopQuadAt()

void SkChopQuadAt ( const SkPoint  src[3],
SkPoint  dst[5],
SkScalar  t 
)

Given a src quadratic bezier, chop it at the specified t value, where 0 < t < 1, and return the two new quadratics in dst: dst[0..2] and dst[2..4]

Definition at line 175 of file SkGeometry.cpp.

175 {
176 SkASSERT(t > 0 && t < SK_Scalar1);
177
178 float2 p0 = from_point(src[0]);
179 float2 p1 = from_point(src[1]);
180 float2 p2 = from_point(src[2]);
181 float2 tt(t);
182
183 float2 p01 = interp(p0, p1, tt);
184 float2 p12 = interp(p1, p2, tt);
185
186 dst[0] = to_point(p0);
187 dst[1] = to_point(p01);
188 dst[2] = to_point(interp(p01, p12, tt));
189 dst[3] = to_point(p12);
190 dst[4] = to_point(p2);
191}
static float2 interp(const float2 &v0, const float2 &v1, const float2 &t)
Definition: SkGeometry.cpp:169
static skvx::float2 from_point(const SkPoint &point)
Definition: SkGeometry.h:22
#define SK_Scalar1
Definition: SkScalar.h:18
static SkPoint to_point(SkIPoint p)
Definition: editor.cpp:75

◆ SkChopQuadAtHalf()

void SkChopQuadAtHalf ( const SkPoint  src[3],
SkPoint  dst[5] 
)

Given a src quadratic bezier, chop it at the specified t == 1/2, The new quads are returned in dst[0..2] and dst[2..4]

Definition at line 193 of file SkGeometry.cpp.

193 {
194 SkChopQuadAt(src, dst, 0.5f);
195}
void SkChopQuadAt(const SkPoint src[3], SkPoint dst[5], SkScalar t)
Definition: SkGeometry.cpp:175

◆ SkChopQuadAtMaxCurvature()

int SkChopQuadAtMaxCurvature ( const SkPoint  src[3],
SkPoint  dst[5] 
)

Given 3 points on a quadratic bezier, divide it into 2 quadratics if the point of maximum curvature exists on the quad segment. Depending on what is returned, dst[] is treated as follows 1 dst[0..2] is the original quad 2 dst[0..2] and dst[2..4] are the two new quads If dst == null, it is ignored and only the count is returned.

Definition at line 367 of file SkGeometry.cpp.

367 {
369 if (t > 0 && t < 1) {
370 SkChopQuadAt(src, dst, t);
371 return 2;
372 } else {
373 memcpy(dst, src, 3 * sizeof(SkPoint));
374 return 1;
375 }
376}
SkScalar SkFindQuadMaxCurvature(const SkPoint src[3])
Definition: SkGeometry.cpp:344

◆ SkChopQuadAtMidTangent()

void SkChopQuadAtMidTangent ( const SkPoint  src[3],
SkPoint  dst[5] 
)
inline

Given a src quadratic bezier, chop it at the tangent whose angle is halfway between the tangents at p0 and p2. The new quads are returned in dst[0..2] and dst[2..4].

Definition at line 91 of file SkGeometry.h.

91 {
93}
void SkChopQuadAt(const SkPoint src[3], SkPoint dst[5], SkScalar t)
Definition: SkGeometry.cpp:175
float SkFindQuadMidTangent(const SkPoint src[3])
Definition: SkGeometry.cpp:231

◆ SkChopQuadAtXExtrema()

int SkChopQuadAtXExtrema ( const SkPoint  src[3],
SkPoint  dst[5] 
)

Definition at line 307 of file SkGeometry.cpp.

307 {
308 SkASSERT(src);
309 SkASSERT(dst);
310
311 SkScalar a = src[0].fX;
312 SkScalar b = src[1].fX;
313 SkScalar c = src[2].fX;
314
315 if (is_not_monotonic(a, b, c)) {
316 SkScalar tValue;
317 if (valid_unit_divide(a - b, a - b - b + c, &tValue)) {
318 SkChopQuadAt(src, dst, tValue);
320 return 1;
321 }
322 // if we get here, we need to force dst to be monotonic, even though
323 // we couldn't compute a unit_divide value (probably underflow).
324 b = SkScalarAbs(a - b) < SkScalarAbs(b - c) ? a : c;
325 }
326 dst[0].set(a, src[0].fY);
327 dst[1].set(b, src[1].fY);
328 dst[2].set(c, src[2].fY);
329 return 0;
330}
static void flatten_double_quad_extrema(SkScalar coords[14])
Definition: SkGeometry.cpp:272
static int valid_unit_divide(double numer, double denom, double *ratio)
#define SkScalarAbs(x)
Definition: SkScalar.h:39
static bool b
struct MyStruct a[10]

◆ SkChopQuadAtYExtrema()

int SkChopQuadAtYExtrema ( const SkPoint  src[3],
SkPoint  dst[5] 
)

Given 3 points on a quadratic bezier, chop it into 1, 2 beziers such that the resulting beziers are monotonic in Y. This is called by the scan converter. Depending on what is returned, dst[] is treated as follows 0 dst[0..2] is the original quad 1 dst[0..2] and dst[2..4] are the two new quads

Definition at line 279 of file SkGeometry.cpp.

279 {
280 SkASSERT(src);
281 SkASSERT(dst);
282
283 SkScalar a = src[0].fY;
284 SkScalar b = src[1].fY;
285 SkScalar c = src[2].fY;
286
287 if (is_not_monotonic(a, b, c)) {
288 SkScalar tValue;
289 if (valid_unit_divide(a - b, a - b - b + c, &tValue)) {
290 SkChopQuadAt(src, dst, tValue);
292 return 1;
293 }
294 // if we get here, we need to force dst to be monotonic, even though
295 // we couldn't compute a unit_divide value (probably underflow).
296 b = SkScalarAbs(a - b) < SkScalarAbs(b - c) ? a : c;
297 }
298 dst[0].set(src[0].fX, a);
299 dst[1].set(src[1].fX, b);
300 dst[2].set(src[2].fX, c);
301 return 0;
302}

◆ SkClassifyCubic()

SkCubicType SkClassifyCubic ( const SkPoint  p[4],
double  t[2] = nullptr,
double  s[2] = nullptr,
double  d[4] = nullptr 
)

Returns the cubic classification.

t[],s[] are set to the two homogeneous parameter values at which points the lines L & M intersect with K, sorted from smallest to largest and oriented so positive values of the implicit are on the "left" side. For a serpentine curve they are the inflection points. For a loop they are the double point. For a local cusp, they are both equal and denote the cusp point. For a cusp at an infinite parameter value, one will be the local inflection point and the other +inf (t,s = 1,0). If the curve is degenerate (i.e. quadratic or linear) they are both set to a parameter value of +inf (t,s = 1,0).

d[] is filled with the cubic inflection function coefficients. See "Resolution Independent Curve Rendering using Programmable Graphics Hardware", 4.2 Curve Categorization:

If the input points contain infinities or NaN, the return values are undefined.

https://www.microsoft.com/en-us/research/wp-content/uploads/2005/01/p1000-loop.pdf

Definition at line 809 of file SkGeometry.cpp.

809 {
810 // Find the cubic's inflection function, I = [T^3 -3T^2 3T -1] dot D. (D0 will always be 0
811 // for integral cubics.)
812 //
813 // See "Resolution Independent Curve Rendering using Programmable Graphics Hardware",
814 // 4.2 Curve Categorization:
815 //
816 // https://www.microsoft.com/en-us/research/wp-content/uploads/2005/01/p1000-loop.pdf
817 double A1 = calc_dot_cross_cubic(P[0], P[3], P[2]);
818 double A2 = calc_dot_cross_cubic(P[1], P[0], P[3]);
819 double A3 = calc_dot_cross_cubic(P[2], P[1], P[0]);
820
821 double D3 = 3 * A3;
822 double D2 = D3 - A2;
823 double D1 = D2 - A2 + A1;
824
825 // Shift the exponents in D so the largest magnitude falls somewhere in 1..2. This protects us
826 // from overflow down the road while solving for roots and KLM functionals.
827 double Dmax = std::max(std::max(fabs(D1), fabs(D2)), fabs(D3));
828 double norm = previous_inverse_pow2(Dmax);
829 D1 *= norm;
830 D2 *= norm;
831 D3 *= norm;
832
833 if (d) {
834 d[3] = D3;
835 d[2] = D2;
836 d[1] = D1;
837 d[0] = 0;
838 }
839
840 // Now use the inflection function to classify the cubic.
841 //
842 // See "Resolution Independent Curve Rendering using Programmable Graphics Hardware",
843 // 4.4 Integral Cubics:
844 //
845 // https://www.microsoft.com/en-us/research/wp-content/uploads/2005/01/p1000-loop.pdf
846 if (0 != D1) {
847 double discr = 3*D2*D2 - 4*D1*D3;
848 if (discr > 0) { // Serpentine.
849 if (t && s) {
850 double q = 3*D2 + copysign(sqrt(3*discr), D2);
851 write_cubic_inflection_roots(q, 6*D1, 2*D3, q, t, s);
852 }
854 } else if (discr < 0) { // Loop.
855 if (t && s) {
856 double q = D2 + copysign(sqrt(-discr), D2);
857 write_cubic_inflection_roots(q, 2*D1, 2*(D2*D2 - D3*D1), D1*q, t, s);
858 }
859 return SkCubicType::kLoop;
860 } else { // Cusp.
861 if (t && s) {
863 }
865 }
866 } else {
867 if (0 != D2) { // Cusp at T=infinity.
868 if (t && s) {
869 write_cubic_inflection_roots(D3, 3*D2, 1, 0, t, s); // T1=infinity.
870 }
872 } else { // Degenerate.
873 if (t && s) {
874 write_cubic_inflection_roots(1, 0, 1, 0, t, s); // T0=T1=infinity.
875 }
877 }
878 }
879}
static double calc_dot_cross_cubic(const SkPoint &p0, const SkPoint &p1, const SkPoint &p2)
Definition: SkGeometry.cpp:771
static double previous_inverse_pow2(double n)
Definition: SkGeometry.cpp:782
static void write_cubic_inflection_roots(double t0, double s0, double t1, double s1, double *t, double *s)
Definition: SkGeometry.cpp:791
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
struct MyStruct s
static float max(float r, float g, float b)
Definition: hsl.cpp:49
SIN Vec< N, float > sqrt(const Vec< N, float > &x)
Definition: SkVx.h:706

◆ SkConvertQuadToCubic()

void SkConvertQuadToCubic ( const SkPoint  src[3],
SkPoint  dst[4] 
)

Given 3 points on a quadratic bezier, use degree elevation to convert it into the cubic fitting the same curve. The new cubic curve is returned in dst[0..3].

Definition at line 378 of file SkGeometry.cpp.

378 {
379 float2 scale(SkDoubleToScalar(2.0 / 3.0));
380 float2 s0 = from_point(src[0]);
381 float2 s1 = from_point(src[1]);
382 float2 s2 = from_point(src[2]);
383
384 dst[0] = to_point(s0);
385 dst[1] = to_point(s0 + (s1 - s0) * scale);
386 dst[2] = to_point(s2 + (s1 - s2) * scale);
387 dst[3] = to_point(s2);
388}
#define SkDoubleToScalar(x)
Definition: SkScalar.h:64
const Scalar scale

◆ SkCubicIsDegenerate()

static bool SkCubicIsDegenerate ( SkCubicType  type)
inlinestatic

Definition at line 273 of file SkGeometry.h.

273 {
274 switch (type) {
279 return false;
282 return true;
283 }
284 SK_ABORT("Invalid SkCubicType");
285}
#define SK_ABORT(message,...)
Definition: SkAssert.h:70
GLenum type

◆ SkCubicTypeName()

static const char * SkCubicTypeName ( SkCubicType  type)
inlinestatic

Definition at line 287 of file SkGeometry.h.

287 {
288 switch (type) {
289 case SkCubicType::kSerpentine: return "kSerpentine";
290 case SkCubicType::kLoop: return "kLoop";
291 case SkCubicType::kLocalCusp: return "kLocalCusp";
292 case SkCubicType::kCuspAtInfinity: return "kCuspAtInfinity";
293 case SkCubicType::kQuadratic: return "kQuadratic";
294 case SkCubicType::kLineOrPoint: return "kLineOrPoint";
295 }
296 SK_ABORT("Invalid SkCubicType");
297}

◆ SkEvalCubicAt()

void SkEvalCubicAt ( const SkPoint  src[4],
SkScalar  t,
SkPoint locOrNull,
SkVector tangentOrNull,
SkVector curvatureOrNull 
)

Set pt to the point on the src cubic specified by t. t must be 0 <= t <= 1.0

Definition at line 418 of file SkGeometry.cpp.

419 {
420 SkASSERT(src);
421 SkASSERT(t >= 0 && t <= SK_Scalar1);
422
423 if (loc) {
424 *loc = to_point(SkCubicCoeff(src).eval(t));
425 }
426 if (tangent) {
427 // The derivative equation returns a zero tangent vector when t is 0 or 1, and the
428 // adjacent control point is equal to the end point. In this case, use the
429 // next control point or the end points to compute the tangent.
430 if ((t == 0 && src[0] == src[1]) || (t == 1 && src[2] == src[3])) {
431 if (t == 0) {
432 *tangent = src[2] - src[0];
433 } else {
434 *tangent = src[3] - src[1];
435 }
436 if (!tangent->fX && !tangent->fY) {
437 *tangent = src[3] - src[0];
438 }
439 } else {
440 *tangent = eval_cubic_derivative(src, t);
441 }
442 }
443 if (curvature) {
444 *curvature = eval_cubic_2ndDerivative(src, t);
445 }
446}
static SkVector eval_cubic_2ndDerivative(const SkPoint src[4], SkScalar t)
Definition: SkGeometry.cpp:407
static SkVector eval_cubic_derivative(const SkPoint src[4], SkScalar t)
Definition: SkGeometry.cpp:394

◆ SkEvalQuadAt() [1/2]

SkPoint SkEvalQuadAt ( const SkPoint  src[3],
SkScalar  t 
)

Definition at line 144 of file SkGeometry.cpp.

144 {
145 return to_point(SkQuadCoeff(src).eval(t));
146}

◆ SkEvalQuadAt() [2/2]

void SkEvalQuadAt ( const SkPoint  src[3],
SkScalar  t,
SkPoint pt,
SkVector tangent = nullptr 
)

Set pt to the point on the src quadratic specified by t. t must be 0 <= t <= 1.0

Definition at line 132 of file SkGeometry.cpp.

132 {
133 SkASSERT(src);
134 SkASSERT(t >= 0 && t <= SK_Scalar1);
135
136 if (pt) {
137 *pt = SkEvalQuadAt(src, t);
138 }
139 if (tangent) {
140 *tangent = SkEvalQuadTangentAt(src, t);
141 }
142}
SkVector SkEvalQuadTangentAt(const SkPoint src[3], SkScalar t)
Definition: SkGeometry.cpp:148
void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint *pt, SkVector *tangent)
Definition: SkGeometry.cpp:132

◆ SkEvalQuadTangentAt()

SkPoint SkEvalQuadTangentAt ( const SkPoint  src[3],
SkScalar  t 
)

Definition at line 148 of file SkGeometry.cpp.

148 {
149 // The derivative equation is 2(b - a +(a - 2b +c)t). This returns a
150 // zero tangent vector when t is 0 or 1, and the control point is equal
151 // to the end point. In this case, use the quad end points to compute the tangent.
152 if ((t == 0 && src[0] == src[1]) || (t == 1 && src[1] == src[2])) {
153 return src[2] - src[0];
154 }
155 SkASSERT(src);
156 SkASSERT(t >= 0 && t <= SK_Scalar1);
157
158 float2 P0 = from_point(src[0]);
159 float2 P1 = from_point(src[1]);
160 float2 P2 = from_point(src[2]);
161
162 float2 B = P1 - P0;
163 float2 A = P2 - P1 - B;
164 float2 T = A * t + B;
165
166 return to_vector(T + T);
167}
#define B

◆ SkFindBisector()

SkVector SkFindBisector ( SkVector  a,
SkVector  b 
)

Returns a new, arbitrarily scaled vector that bisects the given vectors. The returned bisector will always point toward the interior of the provided vectors.

Definition at line 204 of file SkGeometry.cpp.

204 {
205 std::array<SkVector, 2> v;
206 if (a.dot(b) >= 0) {
207 // a,b are within +/-90 degrees apart.
208 v = {a, b};
209 } else if (a.cross(b) >= 0) {
210 // a,b are >90 degrees apart. Find the bisector of their interior normals instead. (Above 90
211 // degrees, the original vectors start cancelling each other out which eventually becomes
212 // unstable.)
213 v[0].set(-a.fY, +a.fX);
214 v[1].set(+b.fY, -b.fX);
215 } else {
216 // a,b are <-90 degrees apart. Find the bisector of their interior normals instead. (Below
217 // -90 degrees, the original vectors start cancelling each other out which eventually
218 // becomes unstable.)
219 v[0].set(+a.fY, -a.fX);
220 v[1].set(-b.fY, +b.fX);
221 }
222 // Return "normalize(v[0]) + normalize(v[1])".
223 skvx::float2 x0_x1{v[0].fX, v[1].fX};
224 skvx::float2 y0_y1{v[0].fY, v[1].fY};
225 auto invLengths = 1.0f / sqrt(x0_x1 * x0_x1 + y0_y1 * y0_y1);
226 x0_x1 *= invLengths;
227 y0_y1 *= invLengths;
228 return SkPoint{x0_x1[0] + x0_x1[1], y0_y1[0] + y0_y1[1]};
229}

◆ SkFindCubicCusp()

SkScalar SkFindCubicCusp ( const SkPoint  src[4])

Returns t value of cusp if cubic has one; returns -1 otherwise.

Definition at line 1112 of file SkGeometry.cpp.

1112 {
1113 // When the adjacent control point matches the end point, it behaves as if
1114 // the cubic has a cusp: there's a point of max curvature where the derivative
1115 // goes to zero. Ideally, this would be where t is zero or one, but math
1116 // error makes not so. It is not uncommon to create cubics this way; skip them.
1117 if (src[0] == src[1]) {
1118 return -1;
1119 }
1120 if (src[2] == src[3]) {
1121 return -1;
1122 }
1123 // Cubics only have a cusp if the line segments formed by the control and end points cross.
1124 // Detect crossing if line ends are on opposite sides of plane formed by the other line.
1125 if (on_same_side(src, 0, 2) || on_same_side(src, 2, 0)) {
1126 return -1;
1127 }
1128 // Cubics may have multiple points of maximum curvature, although at most only
1129 // one is a cusp.
1130 SkScalar maxCurvature[3];
1131 int roots = SkFindCubicMaxCurvature(src, maxCurvature);
1132 for (int index = 0; index < roots; ++index) {
1133 SkScalar testT = maxCurvature[index];
1134 if (0 >= testT || testT >= 1) { // no need to consider max curvature on the end
1135 continue;
1136 }
1137 // A cusp is at the max curvature, and also has a derivative close to zero.
1138 // Choose the 'close to zero' meaning by comparing the derivative length
1139 // with the overall cubic size.
1140 SkVector dPt = eval_cubic_derivative(src, testT);
1141 SkScalar dPtMagnitude = SkPointPriv::LengthSqd(dPt);
1142 SkScalar precision = calc_cubic_precision(src);
1143 if (dPtMagnitude < precision) {
1144 // All three max curvature t values may be close to the cusp;
1145 // return the first one.
1146 return testT;
1147 }
1148 }
1149 return -1;
1150}
static SkScalar calc_cubic_precision(const SkPoint src[4])
static bool on_same_side(const SkPoint src[4], int testIndex, int lineIndex)
static SkScalar LengthSqd(const SkPoint &pt)
Definition: SkPointPriv.h:63

◆ SkFindCubicExtrema()

int SkFindCubicExtrema ( SkScalar  a,
SkScalar  b,
SkScalar  c,
SkScalar  d,
SkScalar  tValues[2] 
)

Given the 4 coefficients for a cubic bezier (either X or Y values), look for extrema, and return the number of t-values that are found that represent these extrema. If the cubic has no extrema betwee (0..1) exclusive, the function returns 0. Returned count tValues[] 0 ignored 1 0 < tValues[0] < 1 2 0 < tValues[0] < tValues[1] < 1

Cubic'(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 betwee 0 < t < 1

Definition at line 454 of file SkGeometry.cpp.

455 {
456 // we divide A,B,C by 3 to simplify
457 SkScalar A = d - a + 3*(b - c);
458 SkScalar B = 2*(a - b - b + c);
459 SkScalar C = b - a;
460
461 return SkFindUnitQuadRoots(A, B, C, tValues);
462}
int SkFindUnitQuadRoots(SkScalar A, SkScalar B, SkScalar C, SkScalar roots[2])
Definition: SkGeometry.cpp:95

◆ SkFindCubicInflections()

int SkFindCubicInflections ( const SkPoint  src[4],
SkScalar  tValues[2] 
)

Given a cubic bezier, return 0, 1, or 2 t-values that represent the inflection points.

http://www.faculty.idc.ac.il/arik/quality/appendixA.html

Inflection means that curvature is zero. Curvature is [F' x F''] / [F'^3] So we solve F'x X F''y - F'y X F''y == 0 After some canceling of the cubic term, we get A = b - a B = c - 2b + a C = d - 3c + 3b - a (BxCy - ByCx)t^2 + (AxCy - AyCx)t + AxBy - AyBx == 0

Definition at line 741 of file SkGeometry.cpp.

741 {
742 SkScalar Ax = src[1].fX - src[0].fX;
743 SkScalar Ay = src[1].fY - src[0].fY;
744 SkScalar Bx = src[2].fX - 2 * src[1].fX + src[0].fX;
745 SkScalar By = src[2].fY - 2 * src[1].fY + src[0].fY;
746 SkScalar Cx = src[3].fX + 3 * (src[1].fX - src[2].fX) - src[0].fX;
747 SkScalar Cy = src[3].fY + 3 * (src[1].fY - src[2].fY) - src[0].fY;
748
749 return SkFindUnitQuadRoots(Bx*Cy - By*Cx,
750 Ax*Cy - Ay*Cx,
751 Ax*By - Ay*Bx,
752 tValues);
753}

◆ SkFindCubicMaxCurvature()

int SkFindCubicMaxCurvature ( const SkPoint  src[4],
SkScalar  tValues[3] 
)

Definition at line 1043 of file SkGeometry.cpp.

1043 {
1044 SkScalar coeffX[4], coeffY[4];
1045 int i;
1046
1047 formulate_F1DotF2(&src[0].fX, coeffX);
1048 formulate_F1DotF2(&src[0].fY, coeffY);
1049
1050 for (i = 0; i < 4; i++) {
1051 coeffX[i] += coeffY[i];
1052 }
1053
1054 int numRoots = solve_cubic_poly(coeffX, tValues);
1055 // now remove extrema where the curvature is zero (mins)
1056 // !!!! need a test for this !!!!
1057 return numRoots;
1058}
static void formulate_F1DotF2(const SkScalar src[], SkScalar coeff[4])
static int solve_cubic_poly(const SkScalar coeff[4], SkScalar tValues[3])
Definition: SkGeometry.cpp:961

◆ SkFindCubicMidTangent()

float SkFindCubicMidTangent ( const SkPoint  src[4])

Given a src cubic bezier, returns the T value whose tangent angle is halfway between the tangents at p0 and p3.

Definition at line 620 of file SkGeometry.cpp.

620 {
621 // Tangents point in the direction of increasing T, so tan0 and -tan1 both point toward the
622 // midtangent. The bisector of tan0 and -tan1 is orthogonal to the midtangent:
623 //
624 // bisector dot midtangent == 0
625 //
626 SkVector tan0 = (src[0] == src[1]) ? src[2] - src[0] : src[1] - src[0];
627 SkVector tan1 = (src[2] == src[3]) ? src[3] - src[1] : src[3] - src[2];
628 SkVector bisector = SkFindBisector(tan0, -tan1);
629
630 // Find the T value at the midtangent. This is a simple quadratic equation:
631 //
632 // midtangent dot bisector == 0, or using a tangent matrix C' in power basis form:
633 //
634 // |C'x C'y|
635 // |T^2 T 1| * |. . | * |bisector.x| == 0
636 // |. . | |bisector.y|
637 //
638 // The coeffs for the quadratic equation we need to solve are therefore: C' * bisector
639 static const skvx::float4 kM[4] = {skvx::float4(-1, 2, -1, 0),
640 skvx::float4( 3, -4, 1, 0),
641 skvx::float4(-3, 2, 0, 0)};
642 auto C_x = fma(kM[0], src[0].fX,
643 fma(kM[1], src[1].fX,
644 fma(kM[2], src[2].fX, skvx::float4(src[3].fX, 0,0,0))));
645 auto C_y = fma(kM[0], src[0].fY,
646 fma(kM[1], src[1].fY,
647 fma(kM[2], src[2].fY, skvx::float4(src[3].fY, 0,0,0))));
648 auto coeffs = C_x * bisector.x() + C_y * bisector.y();
649
650 // Now solve the quadratic for T.
651 float T = 0;
652 float a=coeffs[0], b=coeffs[1], c=coeffs[2];
653 float discr = b*b - 4*a*c;
654 if (discr > 0) { // This will only be false if the curve is a line.
656 } else {
657 // This is a 0- or 360-degree flat line. It doesn't have single points of midtangent.
658 // (tangent == midtangent at every point on the curve except the cusp points.)
659 // Chop in between both cusps instead, if any. There can be up to two cusps on a flat line,
660 // both where the tangent is perpendicular to the starting tangent:
661 //
662 // tangent dot tan0 == 0
663 //
664 coeffs = C_x * tan0.x() + C_y * tan0.y();
665 a = coeffs[0];
666 b = coeffs[1];
667 if (a != 0) {
668 // We want the point in between both cusps. The midpoint of:
669 //
670 // (-b +/- sqrt(b^2 - 4*a*c)) / (2*a)
671 //
672 // Is equal to:
673 //
674 // -b / (2*a)
675 T = -b / (2*a);
676 }
677 if (!(T > 0 && T < 1)) { // Use "!(positive_logic)" so T=NaN will take this branch.
678 // Either the curve is a flat line with no rotation or FP precision failed us. Chop at
679 // .5.
680 T = .5;
681 }
682 return T;
683 }
684}
SkVector SkFindBisector(SkVector a, SkVector b)
Definition: SkGeometry.cpp:204
static float solve_quadratic_equation_for_midtangent(float a, float b, float c, float discr)
Definition: SkGeometry.cpp:602
static skvx::float4 fma(const skvx::float4 &f, float m, const skvx::float4 &a)
Definition: SkGeometry.cpp:597
Vec< 4, float > float4
Definition: SkVx.h:1146
constexpr float y() const
Definition: SkPoint_impl.h:187
constexpr float x() const
Definition: SkPoint_impl.h:181

◆ SkFindQuadExtrema()

int SkFindQuadExtrema ( SkScalar  a,
SkScalar  b,
SkScalar  c,
SkScalar  tValue[1] 
)

Given the 3 coefficients for a quadratic bezier (either X or Y values), look for extrema, and return the number of t-values that are found that represent these extrema. If the quadratic has no extrema betwee (0..1) exclusive, the function returns 0. Returned count tValues[] 0 ignored 1 0 < tValues[0] < 1

Quad'(t) = At + B, where A = 2(a - 2b + c) B = 2(b - a) Solve for t, only if it fits between 0 < t < 1

Definition at line 265 of file SkGeometry.cpp.

265 {
266 /* At + B == 0
267 t = -B / A
268 */
269 return valid_unit_divide(a - b, a - b - b + c, tValue);
270}

◆ SkFindQuadMaxCurvature()

SkScalar SkFindQuadMaxCurvature ( const SkPoint  src[3])

Given 3 points on a quadratic bezier, if the point of maximum curvature exists on the segment, returns the t value for this point along the curve. Otherwise it will return a value of 0.

Definition at line 344 of file SkGeometry.cpp.

344 {
345 SkScalar Ax = src[1].fX - src[0].fX;
346 SkScalar Ay = src[1].fY - src[0].fY;
347 SkScalar Bx = src[0].fX - src[1].fX - src[1].fX + src[2].fX;
348 SkScalar By = src[0].fY - src[1].fY - src[1].fY + src[2].fY;
349
350 SkScalar numer = -(Ax * Bx + Ay * By);
351 SkScalar denom = Bx * Bx + By * By;
352 if (denom < 0) {
353 numer = -numer;
354 denom = -denom;
355 }
356 if (numer <= 0) {
357 return 0;
358 }
359 if (numer >= denom) { // Also catches denom=0.
360 return 1;
361 }
362 SkScalar t = numer / denom;
363 SkASSERT((0 <= t && t < 1) || SkIsNaN(t));
364 return t;
365}
static constexpr bool SkIsNaN(T x)

◆ SkFindQuadMidTangent()

float SkFindQuadMidTangent ( const SkPoint  src[3])

Given a src quadratic bezier, returns the T value whose tangent angle is halfway between the tangents at p0 and p3.

Definition at line 231 of file SkGeometry.cpp.

231 {
232 // Tangents point in the direction of increasing T, so tan0 and -tan1 both point toward the
233 // midtangent. The bisector of tan0 and -tan1 is orthogonal to the midtangent:
234 //
235 // n dot midtangent = 0
236 //
237 SkVector tan0 = src[1] - src[0];
238 SkVector tan1 = src[2] - src[1];
239 SkVector bisector = SkFindBisector(tan0, -tan1);
240
241 // The midtangent can be found where (F' dot bisector) = 0:
242 //
243 // 0 = (F'(T) dot bisector) = |2*T 1| * |p0 - 2*p1 + p2| * |bisector.x|
244 // |-2*p0 + 2*p1 | |bisector.y|
245 //
246 // = |2*T 1| * |tan1 - tan0| * |nx|
247 // |2*tan0 | |ny|
248 //
249 // = 2*T * ((tan1 - tan0) dot bisector) + (2*tan0 dot bisector)
250 //
251 // T = (tan0 dot bisector) / ((tan0 - tan1) dot bisector)
252 float T = sk_ieee_float_divide(tan0.dot(bisector), (tan0 - tan1).dot(bisector));
253 if (!(T > 0 && T < 1)) { // Use "!(positive_logic)" so T=nan will take this branch.
254 T = .5; // The quadratic was a line or near-line. Just chop at .5.
255 }
256
257 return T;
258}
float dot(const SkVector &vec) const
Definition: SkPoint_impl.h:554

◆ SkFindUnitQuadRoots()

int SkFindUnitQuadRoots ( SkScalar  A,
SkScalar  B,
SkScalar  C,
SkScalar  roots[2] 
)

Given a quadratic equation Ax^2 + Bx + C = 0, return 0, 1, 2 roots for the equation.

From Numerical Recipes in C.

Q = -1/2 (B + sign(B) sqrt[B*B - 4*A*C]) x1 = Q / A x2 = C / Q

Definition at line 95 of file SkGeometry.cpp.

95 {
97
98 if (A == 0) {
99 return return_check_zero(valid_unit_divide(-C, B, roots));
100 }
101
102 SkScalar* r = roots;
103
104 // use doubles so we don't overflow temporarily trying to compute R
105 double dr = (double)B * B - 4 * (double)A * C;
106 if (dr < 0) {
107 return return_check_zero(0);
108 }
109 dr = sqrt(dr);
111 if (!SkIsFinite(R)) {
112 return return_check_zero(0);
113 }
114
115 SkScalar Q = (B < 0) ? -(B-R)/2 : -(B+R)/2;
116 r += valid_unit_divide(Q, A, r);
117 r += valid_unit_divide(C, Q, r);
118 if (r - roots == 2) {
119 if (roots[0] > roots[1]) {
120 using std::swap;
121 swap(roots[0], roots[1]);
122 } else if (roots[0] == roots[1]) { // nearly-equal?
123 r -= 1; // skip the double root
124 }
125 }
126 return return_check_zero((int)(r - roots));
127}
static bool SkIsFinite(T x, Pack... values)
void swap(sk_sp< T > &a, sk_sp< T > &b)
Definition: SkRefCnt.h:341
#define C(TEST_CATEGORY)
Definition: colrv1.cpp:248
#define R(r)

◆ SkMeasureAngleBetweenVectors()

float SkMeasureAngleBetweenVectors ( SkVector  a,
SkVector  b 
)

Measures the angle between two vectors, in the range [0, pi].

Definition at line 197 of file SkGeometry.cpp.

197 {
198 float cosTheta = sk_ieee_float_divide(a.dot(b), sqrtf(a.dot(a) * b.dot(b)));
199 // Pin cosTheta such that if it is NaN (e.g., if a or b was 0), then we return acos(1) = 0.
200 cosTheta = std::max(std::min(1.f, cosTheta), -1.f);
201 return acosf(cosTheta);
202}
static float min(float r, float g, float b)
Definition: hsl.cpp:48

◆ SkMeasureNonInflectCubicRotation()

float SkMeasureNonInflectCubicRotation ( const  SkPoint[4])

Given a cubic curve with no inflection points, this method measures the rotation in radians.

Rotation is perhaps easiest described via a driving analogy: If you drive your car along the curve from p0 to p3, then by the time you arrive at p3, how many radians will your car have rotated? This is not quite the same as the vector inside the tangents at the endpoints, even without inflection, because the curve might rotate around the outside of the tangents (>= 180 degrees) or the inside (<= 180 degrees).

Cubics can have rotations in the range [0, 2*pi].

NOTE: The caller must either call SkChopCubicAtInflections or otherwise prove that the provided cubic has no inflection points prior to calling this method.

Definition at line 579 of file SkGeometry.cpp.

579 {
580 SkVector a = pts[1] - pts[0];
581 SkVector b = pts[2] - pts[1];
582 SkVector c = pts[3] - pts[2];
583 if (a.isZero()) {
585 }
586 if (b.isZero()) {
588 }
589 if (c.isZero()) {
591 }
592 // Postulate: When no points are colocated and there are no inflection points in T=0..1, the
593 // rotation is: 360 degrees, minus the angle [p0,p1,p2], minus the angle [p1,p2,p3].
595}
float SkMeasureAngleBetweenVectors(SkVector a, SkVector b)
Definition: SkGeometry.cpp:197
#define SK_ScalarPI
Definition: SkScalar.h:21
bool isZero() const
Definition: SkPoint_impl.h:193

◆ SkMeasureQuadRotation()

float SkMeasureQuadRotation ( const SkPoint  pts[3])
inline

Measures the rotation of the given quadratic curve in radians.

Rotation is perhaps easiest described via a driving analogy: If you drive your car along the curve from p0 to p2, then by the time you arrive at p2, how many radians will your car have rotated? For a quadratic this is the same as the vector inside the tangents at the endpoints.

Quadratics can have rotations in the range [0, pi].

Definition at line 79 of file SkGeometry.h.

79 {
80 return SkMeasureAngleBetweenVectors(pts[1] - pts[0], pts[2] - pts[1]);
81}
float SkMeasureAngleBetweenVectors(SkVector, SkVector)
Definition: SkGeometry.cpp:197

◆ times_2()

static skvx::float2 times_2 ( const skvx::float2 value)
static

Definition at line 32 of file SkGeometry.h.

32 {
33 return value + value;
34}
uint8_t value

◆ to_point()

static SkPoint to_point ( const skvx::float2 x)
inlinestatic

Definition at line 26 of file SkGeometry.h.

26 {
27 SkPoint point;
28 x.store(&point);
29 return point;
30}