41 "Invalid test case. Should have 4 input points.");
43 "Invalid test case. t %f should be in [0, 1]", t);
46 "Invalid test case. Should have 7 output points.");
52 std::memcpy(&input.
fPts[0], curveInputs.
begin(), 8 *
sizeof(
double));
55 for (
int i = 0;
i < 7; ++
i) {
59 "(%.16f, %.16f) != (%.16f, %.16f) at index %d",
60 expectedOutputs[
i].x, expectedOutputs[
i].y,
68 std::memcpy(input, curveInputs.
begin(), 8 *
sizeof(
double));
71 for (
int i = 0;
i < 7; ++
i) {
75 "(%.16f, %.16f) != (%.16f, %.16f) at index %d",
76 expectedOutputs[
i].
x, expectedOutputs[
i].
y,
84 {{ 0, 0 }, { .12, 1.8 }, { .92, -1.65 }, { 1.0, 1.0 }},
86 {{ 0.000000, 0.000000 }, { 0.000000, 0.000000 }, { 0.000000, 0.000000 },
87 { 0.000000, 0.000000 },
88 { 0.120000, 1.800000 }, { 0.920000, -1.650000 }, { 1.000000, 1.000000 }}
92 {{ 0, 0 }, { .12, 1.8 }, { .92, -1.65 }, { 1.0, 1.0 }},
94 {{ 0.000000, 0.000000 }, { 0.012000, 0.180000 }, { 0.030800, 0.307500 },
95 { 0.055000, 0.393850 },
96 { 0.272800, 1.171000 }, { 0.928000, -1.385000 }, { 1.000000, 1.000000 }}
100 {{ 0, 0 }, { .12, 1.8 }, { .92, -1.65 }, { 1.0, 1.0 }},
102 {{ 0.000000, 0.000000 }, { 0.024000, 0.360000 }, { 0.075200, 0.510000 },
103 { 0.142400, 0.540800 },
104 { 0.411200, 0.664000 }, { 0.936000, -1.120000 }, { 1.000000, 1.000000 }}
108 {{ 0, 0 }, { .12, 1.8 }, { .92, -1.65 }, { 1.0, 1.0 }},
110 {{ 0.000000, 0.000000 }, { 0.036000, 0.540000 }, { 0.133200, 0.607500 },
111 { 0.253800, 0.508950 },
112 { 0.535200, 0.279000 }, { 0.944000, -0.855000 }, { 1.000000, 1.000000 }}
116 {{ 0, 0 }, { .12, 1.8 }, { .92, -1.65 }, { 1.0, 1.0 }},
118 {{ 0.000000, 0.000000 }, { 0.048000, 0.720000 }, { 0.204800, 0.600000 },
119 { 0.380800, 0.366400 },
120 { 0.644800, 0.016000 }, { 0.952000, -0.590000 }, { 1.000000, 1.000000 }}
124 {{ 0, 0 }, { .12, 1.8 }, { .92, -1.65 }, { 1.0, 1.0 }},
126 {{ 0.000000, 0.000000 }, { 0.060000, 0.900000 }, { 0.290000, 0.487500 },
127 { 0.515000, 0.181250 },
128 { 0.740000, -0.125000 }, { 0.960000, -0.325000 }, { 1.000000, 1.000000 }}
132 {{ 0, 0 }, { .12, 1.8 }, { .92, -1.65 }, { 1.0, 1.0 }},
134 {{ 0.000000, 0.000000 }, { 0.072000, 1.080000 }, { 0.388800, 0.270000 },
135 { 0.648000, 0.021600 },
136 { 0.820800, -0.144000 }, { 0.968000, -0.060000 }, { 1.000000, 1.000000 }}
140 {{ 0, 0 }, { .12, 1.8 }, { .92, -1.65 }, { 1.0, 1.0 }},
142 {{ 0.000000, 0.000000 }, { 0.084000, 1.260000 }, { 0.501200, -0.052500 },
143 { 0.771400, -0.044450 },
144 { 0.887200, -0.041000 }, { 0.976000, 0.205000 }, { 1.000000, 1.000000 }}
148 {{ 0, 0 }, { .12, 1.8 }, { .92, -1.65 }, { 1.0, 1.0 }},
150 {{ 0.000000, 0.000000 }, { 0.096000, 1.440000 }, { 0.627200, -0.480000 },
151 { 0.876800, 0.051200 },
152 { 0.939200, 0.184000 }, { 0.984000, 0.470000 }, { 1.000000, 1.000000 }}
156 {{ 0, 0 }, { .12, 1.8 }, { .92, -1.65 }, { 1.0, 1.0 }},
158 {{ 0.000000, 0.000000 }, { 0.108000, 1.620000 }, { 0.766800, -1.012500 },
159 { 0.955800, 0.376650 },
160 { 0.976800, 0.531000 }, { 0.992000, 0.735000 }, { 1.000000, 1.000000 }}
164 {{ 0, 0 }, { .12, 1.8 }, { .92, -1.65 }, { 1.0, 1.0 }},
166 {{ 0.000000, 0.000000 }, { 0.120000, 1.800000 }, { 0.920000, -1.650000 },
167 { 1.000000, 1.000000 },
168 { 1.000000, 1.000000 }, { 1.000000, 1.000000 }, { 1.000000, 1.000000 }}
174 {{ -10, -20 }, { -7, 5 }, { 14, -2 }, { 3, 13 }},
176 {{-10.00000000000000, -20.00000000000000 },
177 { -9.62980000000000, -16.91500000000000 },
178 { -8.98550392000000, -14.31728192000000 },
179 { -8.16106580520000, -12.10537539118400 },
180 { -2.30448192000000, 3.60740632000000 },
181 { 12.64260000000000, -0.14900000000000 },
182 { 3.00000000000000, 13.00000000000000 }}
186 {{ -10, -20 }, { -7, 5 }, { 14, -2 }, { 3, 13 }},
188 {{-10.00000000000000, -20.00000000000000 },
189 { -8.96320000000000, -11.36000000000000 },
190 { -5.77649152000000, -6.54205952000000 },
191 { -2.50378670080000, -3.31715344793600 },
192 { 3.69314048000000, 2.78926592000000 },
193 { 10.19840000000000, 3.18400000000000 },
194 { 3.00000000000000, 13.00000000000000 }}
198 {{ -10, -20 }, { -7, 5 }, { 14, -2 }, { 3, 13 }},
200 {{-10.00000000000000, -20.00000000000000 },
201 { -7.37050000000000, 1.91250000000000 },
202 { 9.08754050000000, -0.75907200000000 },
203 { 5.70546664375000, 8.34743124475000 },
204 { 5.22892800000000, 9.63054950000000 },
205 { 4.35850000000000, 11.14750000000000 },
206 { 3.00000000000000, 13.00000000000000 }}
211 double A,
double B,
double C,
double D,
216 "Invalid test case, up to 2 extrema allowed");
218 const double inputs[8] = {
A, 0,
B, 0,
C, 0,
D, 0};
225 auto [
a,
b, c,
d] = bezier;
230 for (
size_t i = 0;
i < expectedExtrema.
size();
i++) {
231 double t = expectedExtrema[
i];
233 "Invalid test case root %zu. Roots must be in [0, 1]",
i);
234 double shouldBeZero =
a * t * t +
b * t + c;
236 "Invalid test case root %zu. %1.16f != 0",
i, shouldBeZero);
242 double extrema[2] = {0, 0};
245 const double inputs[8] = {
A, 0,
B, 0,
C, 0,
D, 0};
248 "Wrong number of extrema returned %zu != %d",
249 expectedExtrema.
size(), extremaCount);
254 for (
int i = 0;
i < extremaCount;
i++) {
257 "0 != %1.16e at index %d", extrema[
i],
i);
261 "%1.16f != %1.16f at index %d", expectedExtrema[
i], extrema[
i],
i);
277 0.7895966209722478});
289 { 0.0004987532413361362,
337 "Invalid test case. Input curve should have 4 points");
339 "Invalid test case, up to 2 inflection points possible");
341 for (
size_t i = 0;
i < expectedTValues.
size();
i++) {
342 double t = expectedTValues[
i];
344 "Invalid test case t %zu. Should be between 0 and 1 inclusive.",
i);
346 auto inputs =
reinterpret_cast<const double*
>(curveInputs.
data());
352 double curvature = (3 * (Bx * Ay - Ax * By)) * t * t +
353 (3 * (Cx * Ay - Ax * Cy)) * t +
357 "Invalid test case t %zu. 0 != %1.16f.",
i, curvature);
361 "Invalid test case t %zu. Sort intersections in ascending order",
i);
368 for (
int i = 0;
i < 4;
i++) {
369 inputCubic.
fPts[
i].
fX = curveInputs[
i].x;
370 inputCubic.
fPts[
i].
fY = curveInputs[
i].y;
372 double actualTValues[2] = {0, 0};
375 "Wrong number of roots returned %zu != %d", expectedTValues.
size(),
381 for (
int i = 0;
i < inflectionsFound;
i++) {
384 "%.16f != %.16f at index %d", expectedTValues[
i], actualTValues[
i],
i);
393 {{ 4, 0 }, { -3, 4 }, { 7, 4 }, { 0, 8 }},
398 {{ 10, 5 }, { 9, 12 }, { 24, -2 }, { 25, 3 }},
399 { 0.5194234849019033 });
403 {{ 5, 5 }, { 16, 15 }, { 24, -2 }, { 15, 13 }},
405 0.8662808326299419});
408 {{ 3, 6 }, { -3, 4 }, { 4, 5 }, { 0, 6 }},
412 {{ 10, 15 }, { 20, 25 }, { 30, 35 }, { 40, 45 }},
421 bool skipPathops =
false) {
425 "Invalid test case. Input curve should have 4 points");
427 "Invalid test case, up to 3 intersections possible");
429 for (
size_t i = 0;
i < expectedTValues.
size();
i++) {
430 double t = expectedTValues[
i];
432 "Invalid test case t %zu. Should be between 0 and 1 inclusive.",
i);
438 "Invalid test case %zu, %1.16f != %1.16f",
i, xToIntersect,
x);
442 "Invalid test case t %zu. Sort intersections in ascending order",
i);
451 for (
int i = 0;
i < 4;
i++) {
452 inputCubic.
fPts[
i].
fX = curveInputs[
i].x;
453 inputCubic.
fPts[
i].
fY = curveInputs[
i].y;
455 double actualTValues[3] = {0, 0, 0};
459 double extremaAndInflections[6] = {0, 0, 0, 0, 0};
461 int rootCount = inputCubic.
searchRoots(extremaAndInflections, extrema, xToIntersect,
464 "Wrong number of roots returned %zu != %d", expectedTValues.
size(),
470 for (
int i = 0;
i < rootCount;
i++) {
473 "%.16f != %.16f at index %d", expectedTValues[
i], actualTValues[
i],
i);
484 "straight curve crosses once @ 2.0",
485 {{ 0, 0 }, { 0, 0 }, { 10, 10 }, { 10, 10 }},
487 {0.2871407270431519});
490 "straight curve crosses once @ 6.0",
491 {{ 0, 0 }, { 3, 3 }, { 6, 6 }, { 10, 10 }},
493 {0.6378342509269714});
497 "out and back curve exactly touches @ 3.0",
498 {{ 0, 0 }, { 4, 4 }, { 4, 4 }, { 0, 8 }},
502 0.5000610351562500});
505 "out and back curve crosses twice @ 2.0",
506 {{ 0, 0 }, { 4, 4 }, { 4, 4 }, { 0, 8 }},
509 0.7886751294136047});
512 "out and back curve never crosses 4.0",
513 {{ 0, 0 }, { 4, 4 }, { 4, 4 }, { 0, 8 }},
519 "left right left curve crosses three times @ 2.0",
520 {{ 4, 0 }, { -3, 4 }, { 7, 4 }, { 0, 8 }},
522 { 0.1361965624455005,
532 "left right left curve crosses one time @ 1.0",
533 {{ 4, 0 }, { -3, 4 }, { 7, 4 }, { 0, 8 }},
535 { 0.9454060400510326,
540 "left right left curve crosses three times @ 2.5",
541 {{ 4, 0 }, { -3, 4 }, { 7, 4 }, { 0, 8 }},
543 { 0.0898667385750473,
static void testCubicExtrema(skiatest::Reporter *reporter, const std::string &name, double A, double B, double C, double D, SkSpan< const double > expectedExtrema)
static void testChopCubicAtT(skiatest::Reporter *reporter, const std::string &name, SkSpan< const DoublePoint > curveInputs, double t, SkSpan< const DoublePoint > expectedOutputs)
DEF_TEST(ChopCubicAtT_NormalizedCubic, reporter)
static bool nearly_equal(double expected, double actual)
static void testCubicInflectionPoints(skiatest::Reporter *reporter, const std::string &name, SkSpan< const DoublePoint > curveInputs, SkSpan< const double > expectedTValues)
static void testBezierCurveHorizontalIntersectBinarySearch(skiatest::Reporter *reporter, const std::string &name, SkSpan< const DoublePoint > curveInputs, double xToIntersect, SkSpan< const double > expectedTValues, bool skipPathops=false)
bool sk_double_nearly_zero(double a)
bool sk_doubles_nearly_equal_ulps(double a, double b, uint8_t maxUlpsDiff=16)
static std::vector< SkPDFIndirectReference > sort(const THashSet< SkPDFIndirectReference > &src)
bool approximately_equal(double x, double y)
#define REPORTER_ASSERT(r, cond,...)
static std::array< double, 4 > ConvertToPolynomial(const double curve[8], bool yValues)
static std::array< double, 2 > EvalAt(const double curve[8], double t)
static void Subdivide(const double curve[8], double t, double twoCurves[14])
constexpr T * data() const
constexpr T * begin() const
constexpr size_t size() const
static const char * begin(const StringSlice &s)
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
DEF_SWITCHES_START aot vmservice shared library name
SkDCubicPair chopAt(double t) const
int findInflections(double tValues[2]) const
SkDPoint fPts[kPointCount]
static int FindExtrema(const double src[], double tValue[2])
int searchRoots(double extremes[6], int extrema, double axisIntercept, SearchAxis xAxis, double *validRoots) const