我正在尝试从Postscript / SVG路径重建原始图形基元。因此,原始圆圈(在SVG标记中)呈现为:
<path stroke-width="0.5" d="M159.679 141.309
C159.679 141.793 159.286 142.186 158.801 142.186
C158.318 142.186 157.925 141.793 157.925 141.309
C157.925 140.825 158.318 140.432 158.801 140.432
C159.286 140.432 159.679 140.825 159.679 141.309" />
这是使用4条贝塞尔曲线创建圆的近似值。在其他地方,圆弧由链接的贝塞尔曲线近似。
我的问题是,是否有一种算法可用于识别此构造并重建“最佳”圆。我不介意小错误 - 最糟糕的情况是二阶。
更新:请注意,我不知道这是一个圆圈或圆弧 - 它可能是任何东西。曲线上可能有2,3,4或甚至更多的点。所以我真的很喜欢这种类型的功能:
error = getCircleFromPath(path)
其中error
会尽早表明这是否可能是一个圆圈。
[我同意,如果我知道这是一个圆圈,这是一个更容易的问题。]
更新:@george在某种程度上回答了我的问题,但我不认为这是整个故事。
在翻译到原点和标准化后,我似乎在曲线上有以下四点:
point [0, 1] with control point at [+-d,1] // horizontal tangent
point [1, 0] with control point at [1,+-d] // vertical tangent
point [0, -1] with control point at [+-d,-1] // horizontal tangent
point [-1, 0] with control point at [-1,+-d] // vertical tangent
这保证了每个点处的切线与该点处的路径方向“平行”。它还保证了对称性(带有反射的4倍轴。但它不能保证圆形。例如,d
的大值将给出圆形框,小值为圆形钻石。
d
的值似乎约为0.57。这可能是1 / sqrt(3。)或者它可能是别的。这就是我要求的这种关系。
@george给出弧的中点为;
{p1,(p1 + 3 (p2 + p3) + p4)/8,p4}
所以在我的例子中(对于1,0到0,1),这将是:
[[1,0]+3[1,d]+3[d,1]+[0,1]] / 8
即。
[0.5+3d/8, 3d/8+0.5]
如果d = 0.57,则得到0.71,所以d可能是
(sqrt(0.5)-0.5)*8./3.
这适用于方形钻石,但对于圆弧,公式必须更加通用,如果有人拥有它,我将不胜感激。例如,我不熟悉Bezier数学,所以@george的公式对我来说是新的
enter code here
答案 0 :(得分:5)
没有为你做所有的数学运算......这可能会有所帮助:
bezier上总有4个控制点。 您的曲线是4个贝塞尔曲线,它们与控制点1-4,4-7,7-10和10-13相连 对于每个部分。点1,4,7和10(&amp; 13 == 1)恰好位于曲线上。要查看你是否有一个漂亮的圆计算:
center = ( p1+p7 )/2 =( {159.679, 141.309} + {157.925, 141.309} ) / 2
= {158.802, 141.309}
使用积分4 + 10验证您获得相同的结果 - &gt; {158.801,141.309}
一旦你知道了中心,就可以沿着曲线采样点,看看你是否有一个恒定的距离。
如果你只有一个带有4个点的bezier弧,则有用的公式是中点为 (p1 + 3(p2 + p3)+ p4)/ 8。所以你可以找到通过三个点的圆圈:
{p1,(p1 + 3 (p2 + p3) + p4)/8,p4}
再次对曲线上的其他点进行采样,以确定您是否确实有一个近圆弧。
编辑 bezier公式是这样的:
x=(1-t)^3 p1 + 3 (1-t)^2 t p2 + 3 (1-t) t^2 p3 + t^3 p4 with parameter 0 < t < 1
所以例如在t = 1/4你有
x=( 27 p1 + 27 p2 + 9 p3 + 1 p4 ) / 64
因此,一旦找到中心,您可以轻松检查几个点并计算它们的距离。
我怀疑如果你只想检测几乎精确的圆弧,那么用一个严格的公差检查两个额外的点就可以了。如果你想检测近似圆形的东西,我会计算一堆点,并使用平均误差作为标准。
答案 1 :(得分:3)
如果您的所有元素都是圆形的,那么您可以通过path.getBBox()
获取尺寸并从那里生成一个圆。在这种情况下,我正在考虑省略号,但您可以轻松地将其转换为实际的circle
元素:
var path = document.getElementById("circle_path");
var bbox = path.getBBox();
var rx = bbox.width/2;
var ry = bbox.height/2;
var cx = bbox.x + rx;
var cy = bbox.y + ry;
var ellipse = document.createElementNS(xmlns, "ellipse");
ellipse.setAttribute("fill", "none");
ellipse.setAttribute("stroke", "red");
ellipse.setAttribute("stroke-width", 0.1);
ellipse.setAttribute("cx", cx);
ellipse.setAttribute("cy", cy);
ellipse.setAttribute("rx", rx);
ellipse.setAttribute("ry", ry);
svg.appendChild(ellipse);
你可以在这里看到一个演示:
答案 2 :(得分:1)
Bézier曲线的端点可能 on 圆圈。如果是这样,重建原始圆圈很容易。
另一种可能性是将控制点的重心作为圆的中心,因为控制点可能围绕中心对称布局。从中心,您可以得到半径作为最靠近中心的四个控制点的平均距离。
答案 3 :(得分:0)
可以将椭圆定义为以(0,0)为中心,平移(2个参数),缩放(2个参数)和旋转(1个参数)的单位圆。因此,在每个弧上取五个点(t =0¼½¾1)并求解这五个参数。接下来取四个点之间(t =⅛⅛⅜⅝),并测试它们是否位于同一个变换圆上。如果是的话,哇哇哇!,这是一个变形的圆圈(的一部分)。
之前和之后可能是另一个arc
或arcn
。这些椭圆是一样的吗?如果是,并且对接角度接触,则将各部分的描述连接在一起。