/* | |

* Copyright 2023 Google LLC | |

* | |

* Use of this source code is governed by a BSD-style license that can be | |

* found in the LICENSE file. | |

*/ | |

#ifndef SkBezierCurves_DEFINED | |

#define SkBezierCurves_DEFINED | |

#include "include/private/base/SkSpan_impl.h" | |

#include <array> | |

struct SkPoint; | |

/** | |

* Utilities for dealing with cubic Bézier curves. These have a start XY | |

* point, an end XY point, and two control XY points in between. They take | |

* a parameter t which is between 0 and 1 (inclusive) which is used to | |

* interpolate between the start and end points, via a route dictated by | |

* the control points, and return a new XY point. | |

* | |

* We store a Bézier curve as an array of 8 floats or doubles, where | |

* the even indices are the X coordinates, and the odd indices are the Y | |

* coordinates. | |

*/ | |

class SkBezierCubic { | |

public: | |

/** | |

* Evaluates the cubic Bézier curve for a given t. It returns an X and Y coordinate | |

* following the formula, which does the interpolation mentioned above. | |

* X(t) = X_0*(1-t)^3 + 3*X_1*t(1-t)^2 + 3*X_2*t^2(1-t) + X_3*t^3 | |

* Y(t) = Y_0*(1-t)^3 + 3*Y_1*t(1-t)^2 + 3*Y_2*t^2(1-t) + Y_3*t^3 | |

* | |

* t is typically in the range [0, 1], but this function will not assert that, | |

* as Bézier curves are well-defined for any real number input. | |

*/ | |

static std::array<double, 2> EvalAt(const double curve[8], double t); | |

/** | |

* Splits the provided Bézier curve at the location t, resulting in two | |

* Bézier curves that share a point (the end point from curve 1 | |

* and the start point from curve 2 are the same). | |

* | |

* t must be in the interval [0, 1]. | |

* | |

* The provided twoCurves array will be filled such that indices | |

* 0-7 are the first curve (representing the interval [0, t]), and | |

* indices 6-13 are the second curve (representing [t, 1]). | |

*/ | |

static void Subdivide(const double curve[8], double t, | |

double twoCurves[14]); | |

/** | |

* Converts the provided Bézier curve into the the equivalent cubic | |

* f(t) = A*t^3 + B*t^2 + C*t + D | |

* where f(t) will represent Y coordinates over time if yValues is | |

* true and the X coordinates if yValues is false. | |

* | |

* In effect, this turns the control points into an actual line, representing | |

* the x or y values. | |

*/ | |

static std::array<double, 4> ConvertToPolynomial(const double curve[8], bool yValues); | |

static SkSpan<const float> IntersectWithHorizontalLine( | |

SkSpan<const SkPoint> controlPoints, float yIntercept, | |

float intersectionStorage[3]); | |

static SkSpan<const float> Intersect( | |

double AX, double BX, double CX, double DX, | |

double AY, double BY, double CY, double DY, | |

float toIntersect, float intersectionsStorage[3]); | |

}; | |

class SkBezierQuad { | |

public: | |

static SkSpan<const float> IntersectWithHorizontalLine( | |

SkSpan<const SkPoint> controlPoints, float yIntercept, | |

float intersectionStorage[2]); | |

/** | |

* Given | |

* AY*t^2 -2*BY*t + CY = 0 and AX*t^2 - 2*BX*t + CX = 0, | |

* | |

* Find the t where AY*t^2 - 2*BY*t + CY - y = 0, then return AX*t^2 + - 2*BX*t + CX | |

* where t is on [0, 1]. | |

* | |

* - y - is the height of the line which intersects the quadratic. | |

* - intersectionStorage - is the array to hold the return data pointed to in the span. | |

* | |

* Returns a span with the intersections of yIntercept, and the quadratic formed by A, B, | |

* and C. | |

*/ | |

static SkSpan<const float> Intersect( | |

double AX, double BX, double CX, | |

double AY, double BY, double CY, | |

double yIntercept, | |

float intersectionStorage[2]); | |

}; | |

#endif // SkBezierCurves_DEFINED |