如何用 Bézier 曲线创建圆?

发布于 2024-08-10 19:57:03 字数 71 浏览 7 评论 0原文

我们有一个起点 (x, y) 和一个圆半径。还有一个引擎可以从贝塞尔曲线点创建路径。

如何使用贝塞尔曲线创建圆?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

毁梦 2024-08-17 19:57:03

如前所述:没有使用贝塞尔曲线精确表示圆的方法。

要完成其他答案:对于具有 n 段的贝塞尔曲线,到控制点的最佳距离(从曲线中间位于圆本身的意义上来说)是(4/3)*tan(pi/(2n))

n 段的公式

因此,对于 4 个点,它是 (4/3)*tan(pi/8) = 4*(sqrt(2)-1)/3 = 0.552284749831

4 点案例

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)).

formula for n segments

So for 4 points it is (4/3)*tan(pi/8) = 4*(sqrt(2)-1)/3 = 0.552284749831.

4 point case

留一抹残留的笑 2024-08-17 19:57:03

comp.graphics.faq

摘录中有介绍:

主题 4.04:如何将贝塞尔曲线拟合到圆上?

有趣的是,贝塞尔曲线可以逼近一个圆,但是
不完全适合一个圆。
常见的近似是使用四个贝塞尔曲线来模拟一个圆,每个贝塞尔曲线
控制点距终点的距离为 d=r*4*(sqrt(2)-1)/3
(其中 r 是圆半径),并且在与
在端点处画圆。这将确保
贝塞尔曲线在圆上,并且一阶导数是连续的。
该近似值的径向误差约为 0.0273%
圆的半径。

Michael Goldapp,“用三次方近似圆弧
多项式”计算机辅助几何设计 (#8 1991 pp.227-238)

Tor Dokken 和 Morten Daehlen,“圆的良好近似
曲率连续贝塞尔曲线”计算机辅助几何
设计(#7 1990,第 33-41 页)。 http://www.sciencedirect.com/science/article/pii/016783969090019N (非免费文章)

另请参阅非付费文章 http://spencermortensen.com/articles/bezier -circle/

浏览器和 Canvas 元素。

请注意,某些浏览器使用贝塞尔曲线在画布上绘制弧线,Chrome 使用(目前)4 扇区方法,而 Safari 使用 8 扇区方法,差异仅在高分辨率下才明显,因为 0.0273%,而且仅当平行且异相绘制圆弧时才真正可见,您会注意到圆弧从真正的圆振荡。当曲线围绕其径向中心进行动画处理时,效果也更加明显,600 像素半径通常是产生影响的大小。

某些绘图API没有真正的弧线渲染,因此它们也使用贝塞尔曲线,例如Flash平台没有弧线绘图API,因此任何提供弧线的框架通常都使用相同的贝塞尔曲线方法。

请注意,浏览器中的 SVG 引擎可能使用不同的绘图方法。

其他平台

无论您尝试使用什么平台,都值得检查一下圆弧绘制是如何完成的,以便您可以预测此类视觉错误并进行调整。

Covered in the comp.graphics.faq

Excerpt:

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/

Browsers and Canvas Element.

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.

Other platforms

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.

烟织青萝梦 2024-08-17 19:57:03

问题的答案已经很好了,所以没有什么可补充的。受此启发,我开始进行一项实验,以视觉方式确认解决方案,从四条贝塞尔曲线开始,将曲线数量减少到一条。令人惊讶的是,我发现使用三个贝塞尔曲线,圆对我来说看起来足够好,但构造有点棘手。实际上,我使用 Inkscape 将黑色 1 像素宽的贝塞尔曲线近似放置在红色 3 像素宽的圆圈上(由 Inkscape 生成)。为了清楚起见,我添加了显示贝塞尔曲线边界框的蓝色线条和曲面。

为了了解您自己,我将展示我的结果:

1 曲线图(看起来像挤在角落里的水滴,只是为了完整性):在此处输入图像描述

2 条曲线图:在此处输入图像描述

3 曲线图:在此处输入图像描述

4 条曲线图:在此处输入图像描述

(我想将 SVG 或 PDF 放在这里,但不支持)

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) :enter image description here

The 2-curve graph:enter image description here

The 3-curve graph:enter image description here

The 4-curve graph: enter image description here

(I wanted to put the SVG or PDF here, but that isn't supported)

自找没趣 2024-08-17 19:57:03

致那些只是寻找代码的人:
4 件解决方案

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>

这允许绘制由 4 条贝塞尔曲线组成的圆。
用 JS 编写,但可以轻松翻译为任何其他语言

注意

如果需要使用 SVG 路径绘制圆,请不要使用贝塞尔曲线,除非需要这样做。在路径中,您可以使用 Arc 创建 2 个半圆。

使用 SVG 的圆弧路径绘制圆形

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

Note

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.

Circle drawing with SVG's arc path

梦开始←不甜 2024-08-17 19:57:03

已经有很多答案,但我发现了一篇在线小文章,其中有一个非常好的圆的三次贝塞尔近似值。就单位圆而言,c = 0.55191502449,其中 c 是沿切线从轴截点到控制点的距离。

作为单位圆的单象限,以两个中间坐标为控制点。 (0,1),(c,1),(1,c),(1,0)

径向误差仅为 0.019608%,因此我只需将其添加到此答案列表中即可。

这篇文章可以在这里找到用三次贝塞尔曲线逼近圆

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

苦行僧 2024-08-17 19:57:03

这是不可能的。贝塞尔曲线是三次方(至少......最常用的是)。圆不能用三次方精确表示,因为圆的方程中包含平方根。因此,你必须进行近似。

为此,您必须将圆划分为 n 个正切(例如象限、八分圆)。对于每个 n-tant,您使用第一个点和最后一个点作为贝塞尔曲线的第一个点和最后一个点。贝塞尔多边形需要两个附加点。为了快速起见,我会为 n 切线的每个极值点取圆的切线,并选择这两个点作为两条切线的交点(这样基本上你的贝塞尔多边形就是一个三角形)。增加 n-tants 的数量以适合您的精度。

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.

戏蝶舞 2024-08-17 19:57:03

其他答案已经涵盖了一个事实:真正的圆是不可能的。此 SVG 文件是使用二次贝塞尔曲线的近似值,是您可以获得的最接近的文件:http ://en.wikipedia.org/wiki/File:Circle_and_quadratic_bezier.svg

这是三次贝塞尔曲线:http://en.wikipedia.org/wiki/File:Circle_and_cubic_bezier.svg

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

二智少女 2024-08-17 19:57:03

如果您需要 @NoOorZ24 答案的纯 JS 版本。这将返回一个 SVG 路径:

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)
  );
}

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)
  );
}
旧瑾黎汐 2024-08-17 19:57:03

很抱歉让这个死而复生,但我发现这篇文章与

基本上,您可以使用一个非常简单的公式创建一个近圆,该公式允许您使用超过 4 条任意数量的贝塞尔曲线:距离 = radius * stepAngle / 3

其中 距离 是贝塞尔曲线控制点与圆弧最近端点之间的距离,半径是圆的半径,步长角度是圆弧两端之间的角度,如下所示用 2π /(曲线数)表示。

因此,要一击命中:距离 = 半径 * 2π /(曲线数)/ 3

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

他夏了夏天 2024-08-17 19:57:03

这是一个很大的近似值,根据分辨率和精度,看起来合理或糟糕,但我使用 sqrt(2)/2 x radius 作为我的控制点。我读了一篇相当长的文章,介绍了这个数字是如何得出的,它值得一读,但上面的公式既快速又肮脏。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文