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

Posted

技术标签:

【中文标题】如何用贝塞尔曲线创建圆?【英文标题】:How to create circle with Bézier curves? 【发布时间】:2009-11-14 16:33:13 【问题描述】:

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

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

【问题讨论】:

密切相关:Geometrical Arc to Bezier Curve 【参考方案1】:

如前所述:使用贝塞尔曲线无法准确表示圆。

要完成其他答案:对于带有n 的贝塞尔曲线分段,到控制点的 最佳 距离,即曲线的中间位于圆本身上,是 @987654325 @。

所以 4 分是(4/3)*tan(pi/8) = 4*(sqrt(2)-1)/3 = 0.552284749831

【讨论】:

通过最佳距离,您优化了哪些指标?如Approximate a circle with cubic Bézier curves 所示,可能的最低最大漂移是通过不同的值实现的。您能否提供一些链接来定义您的案例中“最佳”的含义,或者公式是如何得出的? @Suma 这对于某些距离来说不是最佳的。将曲线的中间放在圆上是最佳。如果您提出其他标准,当然可以做得更好。 好的。我将尝试改写:“到控制点的距离,使得曲线的中间位于圆本身上”。我认为这是一个有效的决定(足够好且易于计算),但我不会称其为最优(至少在没有写出它是最优的意义上不是)。 这帮助我计算了近似圆八分之一的贝塞尔曲线的控制点。 @legends2k 我使用 LaTeX 和 TikZ 生成 PDF,然后我将其转换为 PNG。【参考方案2】:

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

为了看到你自己,我正在展示我的结果:

1 曲线图(看起来像一滴挤在角落里,只是为了完整性):

2曲线图:

3曲线图:

4 曲线图:

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

【讨论】:

现在,svg 可以作为 html 代码 sn-p 包含进来了。例如看这个答案:***.com/a/32162431 @T S:当我试图用我拥有的 SVG 替换图形时,我意识到我丢失了那些在今年年初被盗的 U 盘。如果时间允许,我会尽快重新创建它们。但是,如果 SVG 可以作为 XML 代码添加(并且不显示为图形),那么这里就没有多大意义了。 如果您的浏览器支持 svg,那么只要您单击“运行代码片段”,就会呈现图像(显然该按钮在移动版的 *** 上不可用...)。请参阅我链接的答案。 @TS:对于较长的文件,恕我直言,这太难看了。【参考方案3】:

包含在 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/ 上的非付费文章

浏览器和画布元素。

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

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

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

其他平台

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

【讨论】:

谢谢,我会替换它。【参考方案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"   style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>

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

注意

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

Circle drawing with SVG's arc path

【讨论】:

这很有帮助,谢谢!需要进行哪些更改才能使 4 个细分市场井然有序?我需要沿着一条路径写文本,但现在它分散在 4 个段中 上面的代码似乎缺少象限的内部,它只是关闭了圆形的外部形状。我认为bezierCurveTo() 之后的另一个ctx.lineTo(centerX, centerY); 可以解决这个问题。 `【参考方案5】:

已经有很多答案了,但我发现了一篇关于圆的三次贝塞尔曲线非常好的小型在线文章。以单位圆表示,c = 0.55191502449 其中 c 是沿切线的轴截点到控制点的距离。

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

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

文章可以在这里找到Approximate a circle with cubic Bézier curves

【讨论】:

你有没有在 *** 的 Mike 'Pomax' Kamermans 上阅读贝塞尔曲线上的 excellent treatise。非常值得一读! :-) @markE 非常感谢您提供的链接,这是我见过的关于该主题的“最优秀”论文之一。迫不及待地想有机会详细了解它.. :D 谢谢... 因此,0.019608% 的误差,当圆的半径超过 2551 像素时,图形将出现 4 个像素的误差,而不是可怕的 0.027253%,因为我们是一个实心的半像素误差(其中图形引擎将更改像素)在 1835 px 导致 2 个像素出错! @Tata​​rize 文章没有说明如何测量误差,它说最大径向漂移?我假设误差沿着曲线 0 我很确定已经查看了误差曲线,即给定的调整只是将点向下移动足以导致弧线上方的最大误差等于弧线下方的最大误差.也就是说,我们将曲线稍微向下更改,因此所有错误都不是正数。这种调整意味着我们要穿越弧线 4 次,最大误差为 4 点。当原始规格线有 2 个点时,即 t=.25 和 t=.75。通过调整,它应该在 t=.125, t=.375 t=.625 t=.875。这假设我们使用的是实心像素而不是抗锯齿,它会在 14 像素处发生变化。【参考方案6】:

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

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

【讨论】:

这是可能的,只要您使用无限数量的零长度贝塞尔曲线。这基本上是无限数量的点,或者更确切地说只是一条弧线。【参考方案7】:

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

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

【讨论】:

【参考方案8】:

我不确定我是否应该提出新问题,因为这是关于近似的,但我对获得任何程度的贝塞尔控制点的通用公式很感兴趣,我相信它适合这个问题。 我在网上找到的所有解决方案都只适用于三次曲线,或者是付费的,或者我什至不明白(我数学不太好)。 所以我决定尝试自己解决这个问题。我正在研究控制点到圆心的距离取决于给定的角度,到目前为止我发现:

其中N 是单曲线的控制点数,α 是圆弧角。

对于二次曲线可以简化为l ≈ r + r * PI*0.1 * pow(α/90, 2) PI*0.1 是一个猜测——我没有计算出完美的价值,但它非常接近。 这对于具有 1-2 个控制点的曲线相当有效,三次曲线的半径误差约为 0.2%。对于更高阶的曲线,精度损失是显着的。 3个控制点曲线看起来类似于二次曲线,所以很明显我错过了一些东西,但我无法弄清楚,这种方法现在通常适合我的需要。 这里是demo。

【讨论】:

这个图片是用什么软件制作的? win 7 + MS Paint 中我的演示 + 数学写作面板(或名称已翻译)的屏幕截图【参考方案9】:

很抱歉让这个人起死回生,但我发现这篇文章以及 this 页面对提出可扩展公式很有帮助。

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

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

所以一击命中:Distance = radius * 2π / (the number of curves) / 3

【讨论】:

这不是圆的最佳近似值。最好的是Distance = (4/3)*tan(pi/2n)。对于大量的弧,它几乎相同,因为tan(pi/2)~pi/2n,但例如对于n=4(这是最常用的情况),您的公式给出Distance=0.5235...,但最佳的是Distance=0.5522...(所以你有〜5 % 错误)。【参考方案10】:

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

【讨论】:

以上是关于如何用贝塞尔曲线创建圆?的主要内容,如果未能解决你的问题,请参考以下文章

贝塞尔曲线基本用法

iOS:贝塞尔曲线(UIBezierPath)-----Swift

贝塞尔曲线

用贝塞尔曲线绘制圆弧

三次贝塞尔曲线画圆的方法。

java如何用描点法绘制双曲线