【问题标题】:Drawing a portion of an ellipse programmatically with a Bezier or an Elliptical path — SVG and raphael.js使用贝塞尔曲线或椭圆路径以编程方式绘制椭圆的一部分 - SVG 和 raphael.js
【发布时间】:2013-04-26 15:59:49
【问题描述】:

我正在尝试以给定的边距围绕椭圆绘制贝塞尔曲线:

我想以编程方式实现这一点,所以如果我改变椭圆大小,曲线就会跟随它。

目前我已经做了这个功能:

function bezierPathTopRounded(ellipse, margin) {
    var box = ellipse.paper.getBBox();

    var leftX = box.x - margin; 

    var rightX = box.x + margin + box.width;

    var y = box.y + box.height/2 - margin; 

    var p = "M "+ leftX  + ", "+ y
    + " C " //could be relative too
    + ( box.x - margin + (box.width/15)  )  + ", " + ( box.y + margin - (box.height/4.5)  ) + " "
    + ( box.x + margin + box.width - (box.width/15)  )  + ", " + ( box.y + margin - (box.height/4.5) ) + " "
    + rightX +", " + y;

    return p;   
}

但我不知道如何计算这个方向点值,以便它适用于任何椭圆:

  • box.width/15
  • box.height/4.5

有一个fiddle with this example

我已阅读此stackoverflow question 并在我的示例中尝试了相同的方法,但仍然无法找到一个简单的解决方案,它仍然是随机的...

编辑

现在我正在尝试使用椭圆形Arc,结果比使用贝塞尔路径更糟糕:

这是我正在使用的功能。如果我删除边距,它会完全按照我的椭圆...最后问题是我如何才能按照椭圆的边距?

function borderPath(ellipse, margin, flag) {
    var flag = flag == undefined ? 1 : 0;

    var box = ellipse.paper.getBBox();

    var leftX = box.x - margin;

    var rightX = box.x + margin + box.width;

    var y = box.y + box.height/2;
    y += (flag == 1) ? -margin : margin;

    var rx = box.width/2 + margin;
    var ry = box.height/2;

    var p = "M "+ leftX + ", "+ y
    + " A "
    + rx + " " + ry
    + " 0 0 "+ flag +" "
    + rightX +", " + y;

    return p;
}

请参阅updated fiddle here

对于糟糕的颜色真的很抱歉,这些都是为了举例。

【问题讨论】:

  • 为什么是贝塞尔?为什么不画另一个适当大小/位置的部分椭圆?
  • 你的意思是椭圆弧?我之前尝试过这个,但由于边距不再是完美的椭圆,这是不可能的。我需要它是一条路径,这样我才能画出这条特定的线。
  • 是的,我的意思是椭圆弧,尽管我明白你的观点,即同心椭圆可能不会产生你想要的效果。话虽如此,我认为贝塞尔曲线只会是一个近似值。你是如何得出box.width/15box.height/4.5 的?不是泛化数学的问题吗?
  • 在拥有这两个数字之前,我尝试了很多。这可能是数学概括的问题,不知道......我会用椭圆弧再试一次,让你知道。
  • 我用椭圆弧更新了,但是结果还是错了……

标签: svg raphael bezier ellipse elliptic-curve


【解决方案1】:

如果你想用贝塞尔曲线来做这件事,你必须决定你想让它看起来有多“错误”。贝塞尔曲线不能表示圆形(以及延伸为椭圆形)曲线,它们只能非常接近,就像多边形一样,只是用更少的截面获得更高的精度。

我在我的贝塞尔曲线入门中分别使用贝塞尔曲线描述了圆逼近和曲线偏移,http://pomax.github.io/bezierinfo/#circles_cubichttp://pomax.github.io/bezierinfo/#offsetting,但如果你是从头开始编码,特别是如果你只需要偏移将是矫枉过正的它是你在你的例子中描述的。

相反,我建议启动 Inkscape 或 Illustrator,打开网格叠加,然后在椭圆周围绘制贝塞尔曲线。让它看起来不错,然后检查坐标是什么,并将其用作在画布程序中实现的足够可靠的信息。您可能不需要在数学上严格正确,只要人们不认为“看起来不对”,您就可以了。

【讨论】:

  • 你的文章不错!我同意他们不可能完全正确的事实,但在我的例子中,它看起来并不那么“错误”,不是吗?我不能用 Inkscape 等来做它们,因为我想根据椭圆为它们设置动画。到目前为止,我的解决方案是为路径(开始,结束)提供 2 个不同的功能。现在如果我想拥有“完美”的曲线,我应该使用椭圆弧吗? — 这也不对,因为它被边缘削减了
  • 使用椭圆弧对您来说可能就足够了,只要您将两个半径偏移相同的量即可。所以如果你的椭圆是 (x,y,r1,r2) 并且你想要一个超过一半椭圆的偏移量,比如 10px,你可以使用 arc(x,y,r1+10,r2+10, pi,2 *pi),最后两个指示弧的开始和结束角度。这里的问题是,如果您使用的是 Canvas2D,目前唯一可用的弧线是圆弧。椭圆弧命令(“ellipse”)终于在更新的草案中(我是请求它的人之一,很高兴它现在已经添加)但还不支持
  • 我正在使用 Raphael(svg 没有画布,所以 A 路径 - rx ry x-axis-rotation large-arc-flag sweep-flag x y)但我会尝试使用此信息找到一种方法,谢谢。
  • 这里似乎需要在椭圆周围等宽边距的外边缘绘制一条细线。如果是这样,则可以将边距计算为法线到椭圆的恒定投影的轨迹 - equation here。我怀疑这样的轨迹是椭圆;对于任何偏心率的椭圆,随着边距宽度的增加,它会趋于圆形。
  • 如果你可以让它工作,那么结果应该很好,但是要编写方程、计算投影和绘制轨迹还有很多工作要做。由于方程是笛卡尔方程,而不是极坐标方程,您可能必须分别处理椭圆的顶部/底部和左侧/右侧弧 - 否则迭代增量将趋于无穷小。
【解决方案2】:

我已经设法根据椭圆及其边距制作椭圆弧。 比我简单地用矩形隐藏我不想要的部分。

这里是函数:

function borderPath(ellipse, flag) {
    var flag = flag == undefined ? 1 : flag;

    var box = ellipse.paper.getBBox();

    var leftX = box.x;

    var rightX = box.x + box.width;

    var y = box.y + box.height/2;

    var rx = box.width/2;
    var ry = box.height/2;

    var p = "M "+ leftX + ", "+ y
    + " A "
    + rx + " " + ry
    + " 0 0 "+ flag +" "
    + rightX +", " + y;

    return p;
}

【讨论】:

    【解决方案3】:

    使用贝塞尔曲线绘制椭圆路径可能会让您头疼。正如您在评论中所说,您正在使用与 RaphaelJS 配合良好的路径弧。

    有关它所期望的所有值的文档,尤其是标志,可以在http://www.svgbasics.com/arcs.html 找到。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-31
      • 2012-12-19
      • 1970-01-01
      • 2011-08-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多