[RFC PATCH 2/5] d2d1: Add cubic bezier bounds functions.
Connor McAdams
conmanx360 at gmail.com
Tue Mar 17 13:20:24 CDT 2020
On Tue, Mar 17, 2020 at 09:04:18PM +0330, Henri Verbeet wrote:
> On Sun, 15 Mar 2020 at 23:20, Connor McAdams <conmanx360 at gmail.com> wrote:
> > +static void d2d_rect_get_cubic_bezier_bounds(D2D_RECT_F *bounds, const D2D1_POINT_2F *p0,
> > + const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2, const D2D1_POINT_2F *p3)
> > +{
> > + D2D1_POINT_2F p, v1, v2, v3, a, b, c;
> > + float root, sq_root;
> > +
> > + if (d2d_check_if_cubic_is_quad(p0, p1, p2, p3))
> > + {
> > + d2d_bezier_cubic_to_quad(p0, p1, p2, p3, &p);
> > + d2d_rect_get_quadratic_bezier_bounds(bounds, p0, &p, p3);
> > + return;
> > + }
> Is that test worth it?
>
Yes, because trying to get the roots of a quadratic that's been upped to
a cubic with the cubic root functions won't get the correct values. You
need to get the derivative of a quadratic for a quadratic, even if it's
been upped to a cubic.
> > + /*
> > + * f(t) = (1 - t)³P₀ + 3(1 - t)²tP₁ + 3(1 - t)t²P₂ + t³P₃
> > + * f'(t) = 3(1 - t)²(P₁ - P₀) + 6(1 - t)t(P₂ - P₁) + 3t²(P₃ - P₂)
> > + *
> > + * Or, from https://pomax.github.io/bezierinfo/#extremities
> > + * V₁ = 3(P₁ - P₀)
> > + * V₂ = 3(P₂ - P₁)
> > + * V₃ = 3(P₃ - P₂)
> > + * f'(t) = V₁(1 - t)² + 2V₂(1 - t)t + V₃t²
> > + * = (V₁ - 2V₂ + V₃)t² + 2(V₂ - V₁)t + V₁
> > + *
> > + * And new quadratic coefficients a, b, and c are:
> > + * a = V₁ - 2V₂ + V₃
> > + * b = 2(V₂ - V₁)
> > + * c = V₁
> > + *
> > + * f'(t) = 0
> > + * t = (-b ± √(b² - 4ac)) / 2a
> > + */
> ...
> > + /* If the square root in the equation is negative, there are no roots. */
> > + if ((sq_root = sqrtf(b.x * b.x - 4.0f * a.x * c.x)) >= 0.0f)
> > + {
> > + root = (-b.x + sq_root) / (2.0f * a.x);
> > + if (root < 1.0f && root > 0.0f)
> > + {
> > + d2d_point_calculate_cubic_bezier(&p, p0, p1, p2, p3, root);
> > + d2d_rect_expand(bounds, &p);
> > + }
> > +
> > + root = (-b.x - sq_root) / (2.0f * a.x);
> > + if (root < 1.0f && root > 0.0f)
> > + {
> > + d2d_point_calculate_cubic_bezier(&p, p0, p1, p2, p3, root);
> > + d2d_rect_expand(bounds, &p);
> > + }
> > + }
> Passing a negative value to sqrtf() won't return a negative result.
> (And it shouldn't, of course.) It'll return NaN.
>
> When the value of √(b² - 4ac) is close to b (i.e., if b² is much
> larger than 4ac), -b + √(b² - 4ac) will have a relatively large error.
> Fortunately, this particular formula has another well-known variant:
>
> 2c / (-b ∓ √(b² - 4ac))
>
> It has the same issue, but in the opposite case, so you can use one
> calculation or the other depending on the sign of b.
Okay, I will change this. Thanks for the insight.
More information about the wine-devel
mailing list