We have a start point (x, y) and a circle radius. There also exists an engine that can create a path from Bézier curve points.
How can I create a circle using Bézier curves?
We have a start point (x, y) and a circle radius. There also exists an engine that can create a path from Bézier curve points.
How can I create a circle using Bézier curves?
As already said: there is no exact representation of the circle using Bezier curves.
To complete the other answers : for Bezier curve with n
segments the optimal distance to the control points, in the sense that the middle of the curve lies on the circle itself, is (4/3)*tan(pi/(2n))
.
So for 4 points it is (4/3)*tan(pi/8) = 4*(sqrt(2)-1)/3 = 0.552284749831
.
1/cos(pi/n)
. –
Unnecessarily 0.552284749831
is not magic anymore! Thanks :) –
Longhair Covered in the comp.graphics.faq
Subject 4.04: How do I fit a Bezier curve to a circle?
Interestingly enough, Bezier curves can approximate a circle but
not perfectly fit a circle.
A common approximation is to use four beziers to model a circle, each
with control points a distance d=r*4*(sqrt(2)-1)/3 from the end points
(where r is the circle radius), and in a direction tangent to the
circle at the end points. This will ensure the mid-points of the
Beziers are on the circle, and that the first derivative is continuous.
The radial error in this approximation will be about 0.0273% of the
circle's radius.
Michael Goldapp, "Approximation of circular arcs by cubic polynomials" Computer Aided Geometric Design (#8 1991 pp.227-238)
Tor Dokken and Morten Daehlen, "Good Approximations of circles by curvature-continuous Bezier curves" Computer Aided Geometric Design (#7 1990 pp. 33-41). http://www.sciencedirect.com/science/article/pii/016783969090019N (non free article)
Also see the non-paywalled article at http://spencermortensen.com/articles/bezier-circle/
Note that some browsers use Bezier curves to their canvas draw arc, Chrome uses (at the present time) a 4 sector approach and Safari uses an 8 sector approach, the difference is noticeable only at high resolution, because of that 0.0273%, and also only truly visible when arcs are drawn in parallel and out of phase, you'll notice the arcs oscillate from a true circle. The effect is also more noticeable when the curve is animating around it's radial center, 600px radius is usually the size where it will make a difference.
Certain drawing API's don't have true arc rendering so they also use Bezier curves, for example the Flash platform has no arc drawing api, so any frameworks that offer arcs are generally using the same Bezier curve approach.
Note that SVG engines within browsers may use a different drawing method.
Whatever platform you are trying to use, it's worth checking to see how arc drawing is done, so you can predict visual errors like this, and adapt.
The answers to the question are very good, so there's little to add. Inspired by that I started to make an experiment to visually confirm the solution, starting with four Bézier curves, reducing the number of curves to one. Amazingly I found out that with three Bézier curves the circle looked good enough for me, but the construction is a bit tricky. Actually I used Inkscape to place the black 1-pixel-wide Bézier approximation over a red 3-pixel-wide circle (as produced by Inkscape). For clarification I added blue lines and surfaces showing the bounding boxes of the Bézier curves.
To see yourself, I'm presenting my results:
The 1-curve graph (which looks like a drop squeezed in a corner, just for completeness) :
(I wanted to put the SVG or PDF here, but that isn't supported)
To people who are just looking for code: 4 piece solution
https://jsfiddle.net/nooorz24/2u9forep/12/
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
function drawBezierOvalQuarter(centerX, centerY, sizeX, sizeY) {
ctx.beginPath();
ctx.moveTo(
centerX - (sizeX),
centerY - (0)
);
ctx.bezierCurveTo(
centerX - (sizeX),
centerY - (0.552 * sizeY),
centerX - (0.552 * sizeX),
centerY - (sizeY),
centerX - (0),
centerY - (sizeY)
);
ctx.stroke();
}
function drawBezierOval(centerX, centerY, sizeX, sizeY) {
drawBezierOvalQuarter(centerX, centerY, -sizeX, sizeY);
drawBezierOvalQuarter(centerX, centerY, sizeX, sizeY);
drawBezierOvalQuarter(centerX, centerY, sizeX, -sizeY);
drawBezierOvalQuarter(centerX, centerY, -sizeX, -sizeY);
}
function drawBezierCircle(centerX, centerY, size) {
drawBezierOval(centerX, centerY, size, size)
}
drawBezierCircle(200, 200, 64)
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
This allows to draw circle that is made out of 4 Bezier curves. Written in JS but can easily be translated to any other language
Don't use Bezier curves if you need to draw a circle using SVG path unless required to do so. In path you can use Arc
to create 2 half circles.
ctx.lineTo(centerX, centerY);
after the bezierCurveTo()
would fix that. ` –
Triumphal Many answers already but I found a small online article with a very good cubic bezier approximation of a circle. In terms of unit circle c = 0.55191502449 where c is the distance from the axis intercept points along the tangents to the control points.
As a single quadrant for the unit circle with the two middle coordinates being the control points. (0,1),(c,1),(1,c),(1,0)
The radial error is just 0.019608% so I just had to add it to this list of answers.
The article can be found here Approximate a circle with cubic Bézier curves
It is not possible. A Bezier is a cubic (at least... the most commonly used is). A circle cannot be expressed exactly with a cubic, because a circle contains a square root in its equation. As a consequence, you have to approximate.
To do this, you have to divide your circle in n-tants (e.g.quadrants, octants). For each n-tant, you use the first and last point as the first and last of the Bezier curve. The Bezier polygon requires two additional points. To be fast, I would take the tangents to the circle for each extreme point of the n-tant and choose the two points as the intersection of the two tangents (so that basically your Bezier polygon is a triangle). Increase the number of n-tants to fit your precision.
The other answers have covered the fact that a true circle is not possible. This SVG file is an approximation using Quadratic Bezier curves, and is the closest thing you can get: http://en.wikipedia.org/wiki/File:Circle_and_quadratic_bezier.svg
Here's one with Cubic Bezier curves: http://en.wikipedia.org/wiki/File:Circle_and_cubic_bezier.svg
In case you need a pure JS version of @NoOorZ24's answer. This will return a SVG path:
function drawBezierOvalQuarter(centerX, centerY, sizeX, sizeY) {
return `
M ${centerX - sizeX} ${centerY}
C ${centerX - sizeX} ${centerY - 0.552 * sizeY},
${centerX - 0.552 * sizeX} ${centerY - sizeY},
${centerX} ${centerY - sizeY}
`;
}
function drawBezierOval(centerX, centerY, sizeX, sizeY) {
return (
drawBezierOvalQuarter(centerX, centerY, -sizeX, sizeY) +
drawBezierOvalQuarter(centerX, centerY, sizeX, sizeY) +
drawBezierOvalQuarter(centerX, centerY, sizeX, -sizeY) +
drawBezierOvalQuarter(centerX, centerY, -sizeX, -sizeY)
);
}
Sorry to bring this one back from the dead, but I found this post very helpful along with this page in coming up with an expandable formula.
Basically, you can create a near circle using an incredibly simple formula that allows you to use any number of Bezier curves over 4: Distance = radius * stepAngle / 3
Where Distance
is the distance between a Bezier control point and the closest end of the arc, radius is the radius
of the circle, and stepAngle
is the angle between the 2 ends of the arc as represented by 2π / (the number of curves).
So to hit it in one shot: Distance = radius * 2π / (the number of curves) / 3
Distance = (4/3)*tan(pi/2n)
. For big number of arcs it is almost the same because tan(pi/2)~pi/2n
, but for example for n=4
(which is the most used case) your formula gives Distance=0.5235...
but the optimal one is Distance=0.5522...
(so you have ~5% error). –
Unnecessarily It's a heavy approximation that will look reasonable or terrible depending on the resolution and precision but I use sqrt(2)/2 x radius as my control points. I read a rather long text how that number is derived and it's worth reading but the formula above is the quick and dirty.
© 2022 - 2024 — McMap. All rights reserved.