4

我正在尝试从 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)

whereerror将早期指示这是否可能是一个圆圈。

[我同意,如果我知道这是一个圆圈,那就更容易解决问题了。]

更新:@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.

这适用于方形菱形,但对于圆弧,公式必须更通用,如果有人拥有它,我将不胜感激。例如,我不熟悉贝塞尔数学,所以@george 的公式对我来说是新的

enter code here
4

4 回答 4

5

无需为您做所有数学运算..这可能会有所帮助:

贝塞尔曲线上总是有 4 个控制点。您的曲线是 4 个贝塞尔曲线,其中点 1-4 、 4-7 、 7-10 和 10-13 是每个部分的控制点。点 1 、 4 、 7 和 10 (&13==1) 正好位于曲线上。看看你是否有一个漂亮的圆圈计算:

center =   ( p1+p7 )/2  =(  {159.679, 141.309} +  {157.925, 141.309} ) / 2
       = {158.802, 141.309}

使用点 4+10 -> {158.801, 141.309} 验证您得到相同的结果

知道中心后,您可以沿曲线采样点,看看您是否有一个恒定的距离。

如果你只有一个 4 点的贝塞尔弧,一个有用的公式是中点位于 (p1 + 3 (p2 + p3) + p4)/8。所以你可以找到经过三个点的圆:

{p1,(p1 + 3 (p2 + p3) + p4)/8,p4}

并再次对曲线上的其他点进行采样,以确定您是否确实有一个近圆弧。

编辑贝塞尔公式是这样的:

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

因此,一旦找到中心,您就可以轻松检查几个点并计算它们的距离。

我怀疑如果您只想检测几乎精确的圆弧,那么检查两个具有严格公差的额外点就可以了。如果你想检测近似圆形的东西,我会计算一堆点并使用平均误差作为标准。

于 2012-10-16T18:16:17.647 回答
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);

你可以在这里看到一个演示:

http://jsfiddle.net/nwHm6/

于 2012-10-16T01:40:03.300 回答
1

贝塞尔曲线的端点可能圆上。如果是这样,很容易重建原来的圆。

另一种可能性是将控制点的重心作为圆的中心,因为控制点可能围绕中心对称布置。从中心,你得到半径作为最接近中心的四个控制点的平均距离。

于 2012-10-16T01:18:04.770 回答
0

可以将椭圆定义为以 (0,0) 为中心、平移 (2 参数)、缩放 (2 参数) 和旋转 (1 参数) 的单位圆。因此,在每条弧上取五个点(t=0 ¼ ½ ¾ 1)并求解这五个参数。接下来取中间的四个点(t=⅛ ⅜ ⅝ ⅞),并测试它们是否位于同一个变换圆上。如果是,哇哦!,这是(一部分)一个变形的圆圈。

紧接在之前和之后可能是另一个arcarcn。这些是同一个椭圆吗?如果是,并且对向的角度相互接触,那么将你对这些作品的描述结合在一起。

于 2013-04-01T13:43:29.120 回答