具有给定段数的近似圆

Posted

技术标签:

【中文标题】具有给定段数的近似圆【英文标题】:approximating circle with given number of segments 【发布时间】:2011-07-12 19:02:33 【问题描述】:

有没有更好的方法从半径和顶点数计算圆? 我的解决方案为每个顶点计算 sincos。有必要吗?

void getCircle2D(Vector2 * perimeterPointsArray, int32 numOfPoints, Vector2 & center, flt32 radius)

    ASSERT(numOfPoints >= 3);
    flt32 pieceAngle = MathConst::TAU / numOfPoints;
    flt32 iterAngle = 0;
    for (int32 i = 0; i < numOfPoints; ++i)
    
        perimeterPointsArray[i] = Vector2(radius * cos(iterAngle) + center.x, radius * sin(iterAngle) + center.y);
        iterAngle += pieceAngle;
    

【问题讨论】:

【参考方案1】:

您建议的方法应该是通常的方法。但也许您可以使用以下加法定理提出迭代计算(请参阅Wikipedia):

sin(a+b) = sin(a)*cos(b) + cos(a)*sin(b)
cos(a+b) = cos(a)*cos(b) - sin(a)*sin(b)

在您的情况下,a 是前一个角度(您刚刚计算了其 cos 和 sin),b 是恒定角度步长(当然,其 cos 和 sin 也是常数)。所以这样的事情可能会起作用:

void getCircle2D(Vector2 * perimeterPointsArray, int32 numOfPoints, Vector2 & center, flt32 radius)

    flt32 pieceAngle = MathConst::TAU / numOfPoints;
    flt32 sinb = sin(pieceAngle), cosb = cos(pieceAngle);
    flt32 sina = 0.0, cosa = 1.0;
    for (int32 i = 0; i < numOfPoints; ++i)
    
        perimeterPointsArray[i] = Vector2(radius * cosa + center.x, radius * sina + center.y);
        flt32 tmp = sina * cosb + cosa * sinb;
        cosa = cosa * cosb - sina * sinb;
        sina = tmp;
    

在这里您只需计算一个 sin 和一个 cos(如果在编译时知道点数,甚至可以预先计算)。

@yi_H 我不知道圆光栅化算法是否真的适合浮点圆近似,但也许在浮点中它可以推广到上面提到的迭代计算。

【讨论】:

【参考方案2】:

你不需要 sin 和 cos:

Midpoint circle algorithm。它用于像素图形,但应该很容易修改它以创建 verices。当然,这只有在顶点数与像素数相当(比如小一个数量级)时才有意义。

【讨论】:

【参考方案3】:

您可以计算一半的点,然后围绕 X 中心镜像。

【讨论】:

你是对的,如果你有这样的严格要求(它应该适用于奇数),那么我不会......但这对我来说听起来不现实。 @yi_H,如果点数是奇数,四分之一不起作用。举个极端的例子,考虑 3 点。 是的,我也说了同样的话。但是你通常用 100 个或更多顶点来近似一个圆,我只是不认为你需要 101 个顶点是一个现实的场景。

以上是关于具有给定段数的近似圆的主要内容,如果未能解决你的问题,请参考以下文章

具有多个圆的近似多边形

java 打印近似圆

冯·米塞斯分布

找到具有权重和惩罚的常见近似子串

如何找到给定 N 切割的无限杆的最大段数

上帝造题的七分钟2