【问题标题】:What algorithm is used for computing a circle with floating point radius?什么算法用于计算具有浮点半径的圆?
【发布时间】:2015-03-21 07:17:43
【问题描述】:

midpoint circle algorithm 非常适合计算半径为整数的圆。

void CircleOptimized(int xc, int yc, int r, int color) {
    unsigned int x= r, y= 0;//local coords     
    int          cd2= 0;    //current distance squared - radius squared
    if (!r) return; 
    drawpixel(xc-r, yc, color);
    drawpixel(xc+r, yc, color);
    drawpixel(xc, yc-r, color);
    drawpixel(xc, yc+r, color);
    while (x > y) {    //only formulate 1/8 of circle
        cd2-= (--x) - (++y);
        if (cd2 < 0) cd2+=x++;
        drawpixel(xc-x, yc-y, color);//upper left left
        drawpixel(xc-y, yc-x, color);//upper upper left
        drawpixel(xc+y, yc-x, color);//upper upper right
        drawpixel(xc+x, yc-y, color);//upper right right
        drawpixel(xc-x, yc+y, color);//lower left left
        drawpixel(xc-y, yc+x, color);//lower lower left
        drawpixel(xc+y, yc+x, color);//lower lower right
        drawpixel(xc+x, yc+y, color);//lower right right
     } 
}

例如,当通过r=1r=2时,输出分别如下:

.....  .XXX.
..X..  X...X
.X.X.  X...X
..X..  X...X
.....  .XXX.
 r=1    r=2

但是,我需要在 r=1r=2 之间再走几步。也许(假设)r=1.33r=1.66 可能看起来像这样:

.....  .....  ..X..  .XXX.
..X..  .XXX.  .X.X.  X...X
.X.X.  .X.X.  X...X  X...X
..X..  .XXX.  .X.X.  X...X
.....  .....  ..X..  .XXX.
r=1.0  r=1.3  r=1.6  r=2.0

但是,当我尝试调整上述算法以使用浮点运算(带或不带舍入)时,它会失去对称性并生成不连续的路径(导致一些非常奇怪的形状)。

有没有更适合我的算法?

【问题讨论】:

  • 那么,您在问为什么您没有显示的代码版本不起作用?看到这里有什么问题吗? ;-)
  • 无论如何,整个算法都是基于整数运算的。要么使用带有缩放比例的整数,要么使用基本的 sincos 公式来计算圆。
  • @hyde 复制并粘贴代码块似乎非常简单,只需将 int 替换为 float,然后再复制并粘贴一个添加的 round
  • @hyde 或者您可以使用圆方程,x^2 + y^2 = r^2。它允许您非常轻松地进行提示(基于等式左侧和右侧之间的差异),并且如果半径相对较低(您似乎正在使用非常小的圆圈),它应该非常快(注意你只需要为四分之一的圆圈做这个 - 其他三个是简单的镜子)。无论如何,您为什么要关心优化圆形绘图?你想解决什么问题?
  • 一种方法是硬编码少数特殊情况,例如 1.3、1.6、2.5。然后使用整数算法其余的。也就是说,如果您不想/不需要抗锯齿,并且不需要更多特殊情况。

标签: c# c++ geometry


【解决方案1】:

如果您只对简单的分数(如 4/3 和 5/3)感兴趣,我会过采样(即使用子像素,这里每个像素 9 个子像素,因此计算半径为 4 和 5 个子像素的圆)和然后从子像素中推断出像素的好值。如果你推断出除 ON 以外的其他东西,则 OFF 你正在做抗锯齿。

【讨论】:

    【解决方案2】:

    基本画圆...

    public void DrawCircle(float stepSize, float radius, int colour)
    {
        float x, y;
        float angle;
    
        while (angle < 2*Math.PI)
        {
            x = radius * cos(angle);
            y = radius * sin(angle);
            // decide how to round your floating point X,Y here ...
            drawpixel(x,y,colour);
            angle += stepSize;
        }
    }
    

    【讨论】:

    • 查找stepdecide how to round 是两个最大的问题。解决它们会比适应中点圆算法更成问题。
    • 好吧,step 就是您想要的圆的平滑程度 - 如果您担心圆的步长太多,您可以根据您的半径提出一个缩放比例.只要你的decide how to round 是一致的(例如,总是向下舍入),那么你就不会得到中点圆算法得到的不连贯的段。
    • 如果您采取的步骤太小,或者您的决定没有考虑为最接近的像素所做的决定 - 您最终会一次绘制 2 个圆圈:删除分数并四舍五入(例如,对于 1.3,它将是 1 和 2)。找到正确的步骤和四舍五入的决定是一项挑战。试着自己画那个小圆圈。我并不是说你的答案是错误的,它是正确的,但它太笼统了,可能不适合给定的问题^^
    【解决方案3】:

    我认为泰勒近似可能有用

    • 使用一阶泰勒近似计算 x^2= r^2- y^2 中的 x (sqrt(u^2 + a) = u + a / 2u)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-07
      • 1970-01-01
      • 1970-01-01
      • 2021-11-09
      • 2021-04-09
      • 1970-01-01
      • 2018-07-28
      • 1970-01-01
      相关资源
      最近更新 更多