Convert quadratic curve to cubic curve

2019-02-09 05:10发布

问题:

Looking at Convert a quadratic bezier to a cubic?, I can finally understand why programming teachers always told me that math was so important. Sadly, I didn't listen.

Can anyone provide a more concrete - e.g., computer-language-y - formula for converting a quadratic curve to a cubic? Understanding that there's some rounding errors possible, which is fine.

Given a quad curve represented by variables:

StartX, StartY
ControlX, ControlY
EndX, EndY

And desiring StartX, StartY and EndX, EndY to remain the same, but to now have Control1X, Control1Y and Control2X, Control2Y of a cubic curve.

Is it...

Control1X = StartX + (.66 * (ControlX - StartX))
Control2X = EndX + (.66 * (ControlX - EndX))

With the same essential functions used to calculate Control1Y and Control2Y?

回答1:

Your code is right except that you should use 2.0/3.0 instead of 0.66.



回答2:

You avoid most rounding errors by using

Control1 = (Start + 2 * Control) / 3
Control2 = (End   + 2 * Control) / 3

Note that line segments are also convertible to cubic Bezier curves using:

Control1 = Start
Control2 = End

This can be handy when converting a complex path mixing various types of curves (linear, quadratic, cubic)

There's also a basic transform for converting elliptic arcs to cubic (with some minor unnoticeable errors): you just have to split at least the arc on elliptic quadrans (cutting the ellipse first on the two ortogonal axis of symetries, or on arbitrary orthogonal axis passing through the center if the ellipse is a circle, then representing each arc ; when the ellipse is a cricle, the two focal points are confused on the same point, the center of the circle).

Many SVG renderers do that by adding an additional split on octants (so that you get also precise position not only for points where the two main axis are passing through, but also for two diagonal axis which are bissecting (when the ellipse is a circle) each quadrant (when the ellipse is not a circle, assimilate it as a circle flattened with a linear transform along the small axis only, you do the same computation), because octants are also quite precisely positioned (cos(pi/4)=sin(pi/4)=sqrt(2)/2 ~ 0.71, and because this additional splitting will allow precise rendering of tangents on points crossing the diagonals at 45 degrees of the circle): a full ellipse is then converted to 8 cubic arcs (I.e. 8 points on ellipse and 16 control points): you'll almost not notice the difference between these elliptical arcs and cubic arcs (you can create an algorithm that uses the same "flattening error" computed when splitting a Bezier to a list of linear segments, which are then drawn using the classic fast Bresenham algo for line segments).


Such transform of arbitrary paths is useful when you want to derive other curves from the path, notably the curves of "buffers" at a given distance, notably when these paths must be converted to "strokes" with a defined "stroke width": you need to compute two "inner" and "outer" curves and then concentrate on how to converting the miters/buts/squares/rounded corners, and then to cut long miters at a convenient distance (matching the "miter limit" factor times the "stroke width").

More advanced renderers will also use miters represented by tangent circles when there's a corner between two arcs instead of two segments (this is useful for drawing cute geographic maps)...

Converting an arbitrary path mixing segments, elliptic and bezier arcs to only cubic is a necessary step to compute precise images without excessive defects visible when zooming in. This is then necessary when your "stroke" buffers have to take some effects (such as computing dashes), and then enhancing the result with semi-transparent pixels or subpixels to smooth the rendered strokes (smoothing is easy to computez only when everything has been flattened to line segments, and alsos may be simpler to develop if it only has to manage paths containing only cubic beziers: it can easily be parallelized if needed and accelerated by hardware).