29 {285.625f, 499.687f}, {411.625f, 808.188f}, {1064.62f, 135.688f}, {1042.63f, 585.187f}};
32 {635.625f, 614.687f}, {171.625f, 236.188f}, {1064.62f, 135.688f}, {516.625f, 570.187f}};
35 {460.625f, 557.187f}, {707.121f, 209.688f}, {779.628f, 577.687f}};
38 float k = (2 * 1) / 8.f * precision;
39 return sqrtf(k * (
p[0] -
p[1]*2 +
p[2]).
length());
43 float k = (3 * 2) / 8.f * precision;
60 float min_x =
P[0].fX, max_x = min_x,
61 min_y =
P[0].fY, max_y = min_y;
62 for (
int i = 1;
i < 3;
i++) {
73 for (
int i = 0;
i < 3;
i++) {
79 const float eps = 1 / precision;
80 const float r_minus_eps =
std::max(0.f, max_len - eps);
82 const float numer = 4 * min_w * eps;
84 (tP[2] - tP[1] * 2 *
w + tP[0]).
length() + r_minus_eps *
std::abs(1 - 2 *
w + 1);
85 const float delta = sqrtf(numer / denom);
88 constexpr float tmin = 0, tmax = 1;
90 return (tmax - tmin) /
delta;
98 for (
int i = -10;
i <= 30; ++
i) {
99 for (
int j = -10; j <= 30; ++j) {
100 m.setScaleX(std::ldexp(1 + rand->
nextF(),
i));
103 m.setScaleY(std::ldexp(1 + rand->
nextF(), j));
106 m.setScaleX(std::ldexp(1 + rand->
nextF(),
i));
107 m.setSkewX(std::ldexp(1 + rand->
nextF(), (j +
i) / 2));
108 m.setSkewY(std::ldexp(1 + rand->
nextF(), (j +
i) / 2));
109 m.setScaleY(std::ldexp(1 + rand->
nextF(), j));
117 int maxExponent = 30) {
120 for (
int i = -10;
i <= maxExponent; ++
i) {
121 for (
int j = 0; j < numPoints; ++j) {
122 pts[j].
set(std::ldexp(1 + rand->
nextF(),
i), std::ldexp(1 + rand->
nextF(),
i));
134 auto setupCubicLengthTerm = [](
int seed,
SkPoint pts[],
float term) {
135 memset(pts, 0,
sizeof(
SkPoint) * 4);
142 term2d.
fX = -term2d.
fX;
154 pts[3] = term2d * .75f;
157 pts[1] = term2d * -.5f;
160 pts[1] = term2d * -.5f;
164 pts[0] = term2d * .75f;
172 auto setupQuadraticLengthTerm = [](
int seed,
SkPoint pts[],
float term) {
173 memset(pts, 0,
sizeof(
SkPoint) * 3);
180 term2d.
fX = -term2d.
fX;
194 pts[1] = term2d * -.5f;
205 constexpr static float kTessellationTolerance = 1/128.f;
215 constexpr static float k = (3 * 2) / (8 * (1.f/
kPrecision));
216 float x = std::ldexp(1,
level * 2) / k;
217 setupCubicLengthTerm(
level << 1, pts,
x - epsilon);
223 setupCubicLengthTerm(
level << 1, pts,
x + epsilon);
234 constexpr static float k = 2 / (8 * (1.f/
kPrecision));
235 float x = std::ldexp(1,
level * 2) / k;
236 setupQuadraticLengthTerm(
level << 1, pts,
x - epsilon);
242 setupQuadraticLengthTerm(
level << 1, pts,
x + epsilon);
251 auto check_cubic_log2 = [&](
const SkPoint* pts) {
259 auto check_quadratic_log2 = [&](
const SkPoint* pts) {
271 m.mapPoints(pts,
kSerp, 4);
272 check_cubic_log2(pts);
274 m.mapPoints(pts,
kLoop, 4);
275 check_cubic_log2(pts);
277 m.mapPoints(pts,
kQuad, 3);
278 check_quadratic_log2(pts);
282 check_cubic_log2(pts);
286 check_quadratic_log2(pts);
292 auto check_cubic_log2_with_transform = [&](
const SkPoint* pts,
const SkMatrix&
m){
294 m.mapPoints(ptsXformed, pts, 4);
300 auto check_quadratic_log2_with_transform = [&](
const SkPoint* pts,
const SkMatrix&
m) {
302 m.mapPoints(ptsXformed, pts, 3);
311 check_cubic_log2_with_transform(
kSerp,
m);
312 check_cubic_log2_with_transform(
kLoop,
m);
313 check_quadratic_log2_with_transform(
kQuad,
m);
316 check_cubic_log2_with_transform(pts,
m);
320 check_quadratic_log2_with_transform(pts,
m);
327 SkPoint worstP[] = {{0,0}, {100,100}, {0,0}, {0,0}};
334 SkPoint worstP[] = {{100,100}, {100,100}, {200,200}, {100,100}};
340 auto check_worst_case_cubic = [&](
const SkPoint* pts) {
351 for (
int i = 0;
i < 100; ++
i) {
353 check_worst_case_cubic(pts);
357 constexpr static float inf = std::numeric_limits<float>::infinity();
367 constexpr int maxExponent = 15;
370 const int nsegs =
static_cast<int>(
373 const float tdelta = 1.f / nsegs;
374 for (
int j = 0; j < nsegs; ++j) {
375 const float tmin = j * tdelta, tmax = (j + 1) * tdelta;
391 sectionPts = tmp0 + 2;
393 SkChopQuadAt(tmp0 + 2, tmp1, (tmax - tmin) / (1 - tmin));
403 const SkPoint n = {sectionPts[2].
fY - sectionPts[0].
fY,
404 sectionPts[0].
fX - sectionPts[2].
fX};
416 constexpr static float kTessellationTolerance = 1 / 128.f;
419 for (
int i = 0;
i < 100; ++
i) {
431 constexpr int maxExponent = 24;
436 const auto eval_conic = [](
const SkPoint pts[3],
float w,
float t) -> Sk2d {
437 const auto eval = [](Sk2d
A, Sk2d
B, Sk2d
C,
float t) -> Sk2d {
438 return (
A * t +
B) * t +
C;
441 const Sk2d p0 = {pts[0].
fX, pts[0].
fY};
442 const Sk2d p1 = {pts[1].
fX, pts[1].
fY};
443 const Sk2d p1w = p1 *
w;
444 const Sk2d p2 = {pts[2].
fX, pts[2].
fY};
445 Sk2d numer = eval(p2 - p1w * 2 + p0, (p1w - p0) * 2, p0, t);
447 Sk2d denomC = {1, 1};
448 Sk2d denomB = {2 * (
w - 1), 2 * (
w - 1)};
449 Sk2d denomA = {-2 * (
w - 1), -2 * (
w - 1)};
450 Sk2d denom = eval(denomA, denomB, denomC, t);
451 return numer / denom;
454 const auto dot = [](
const Sk2d&
a,
const Sk2d&
b) ->
double {
455 return a[0] *
b[0] +
a[1] *
b[1];
458 const auto length = [](
const Sk2d&
p) ->
double {
return sqrt(
p[0] *
p[0] +
p[1] *
p[1]); };
461 for (
int i = -10;
i <= 10; ++
i) {
462 const float w = std::ldexp(1 + rand.
nextF(),
i);
468 const float tdelta = 1.f / nsegs;
469 for (
int j = 0; j < nsegs; ++j) {
470 const float tmin = j * tdelta, tmax = (j + 1) * tdelta,
471 tmid = 0.5f * (tmin + tmax);
474 p0 = eval_conic(pts,
w, tmin);
475 p1 = eval_conic(pts,
w, tmid);
476 p2 = eval_conic(pts,
w, tmax);
479 const Sk2d n = {p2[1] - p0[1], p0[0] - p2[0]};
492DEF_TEST(wangs_formula_conic_matches_reference, r) {
494 for (
int i = -10;
i <= 10; ++
i) {
495 const float w = std::ldexp(1 + rand.
nextF(),
i);
502 const float cmpThresh = ref_nsegs * (1.f / (1 << 20));
510 auto check_conic_with_transform = [&](
const SkPoint* pts,
float w,
const SkMatrix&
m) {
512 m.mapPoints(ptsXformed, pts, 3);
519 for (
int i = -10;
i <= 10; ++
i) {
520 const float w = std::ldexp(1 + rand.
nextF(),
i);
523 check_conic_with_transform(
532 check_conic_with_transform(pts,
w,
m);
538 REPORTER_ASSERT(r, 0b0'00000000'111'1111111111'1111111111 == (1u << 23) - 1u);
572 for (
int i = 0;
i < 100; ++
i) {
573 float pow2 = std::ldexp(1,
i);
void SkChopQuadAt(const SkPoint src[3], SkPoint dst[5], SkScalar t)
void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint *pt, SkVector *tangent)
void swap(sk_sp< T > &a, sk_sp< T > &b)
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
#define SkScalarCeilToInt(x)
#define SK_ScalarNearlyZero
#define REPORTER_ASSERT(r, cond,...)
static SkMatrix Scale(SkScalar sx, SkScalar sy)
static const SkMatrix & I()
float nextRangeF(float min, float max)
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Dart_NativeFunction function
static float max(float r, float g, float b)
static float min(float r, float g, float b)
static void for_random_beziers(int numPoints, SkRandom *rand, const std::function< void(const SkPoint[])> &f, int maxExponent=30)
static void for_random_matrices(SkRandom *rand, const std::function< void(const SkMatrix &)> &f)
static float wangs_formula_conic_reference_impl(float precision, const SkPoint P[3], const float w)
static float wangs_formula_quadratic_reference_impl(float precision, const SkPoint p[3])
DEF_TEST(CullTestTest, reporter)
static constexpr float kPrecision
static float wangs_formula_cubic_reference_impl(float precision, const SkPoint p[4])
SINT T dot(const Vec< N, T > &a, const Vec< N, T > &b)
SIN Vec< N, float > abs(const Vec< N, float > &x)
SIN Vec< N, float > sqrt(const Vec< N, float > &x)
SIN Vec< N, float > ceil(const Vec< N, float > &x)
static constexpr SkPoint Make(float x, float y)
void set(float x, float y)
constexpr float height() const
constexpr float width() const
void setBoundsNoCheck(const SkPoint pts[], int count)