C 中点圆算法 将圆分割成4

C Mid Point Circle Algorithm Split Circle Into 4

在我的程序中,我目前使用中点圆算法和以下代码渲染圆。

void drawcircle(int x0, int y0, int radius)
{
    int x = radius-1;
    int y = 0;
    int dx = 1;
    int dy = 1;
    int err = dx - (radius << 1);

    while (x >= y)
    {
        putpixel(x0 + x, y0 + y);
        putpixel(x0 + y, y0 + x);
        putpixel(x0 - y, y0 + x);
        putpixel(x0 - x, y0 + y);
        putpixel(x0 - x, y0 - y);
        putpixel(x0 - y, y0 - x);
        putpixel(x0 + y, y0 - x);
        putpixel(x0 + x, y0 - y);

        if (err <= 0)
        {
            y++;
            err += dy;
            dy += 2;
        }
        if (err > 0)
        {
            x--;
            dx += 2;
            err += (-radius << 1) + dx;
        }
    }
}

但我的问题是,是否可以让此功能以相同的方式工作,但将圆分成 4 个单独的部分?也就是说,与其渲染一个普通的圆,它看起来有点像这样

在圆圈中打洞

您的实施在 8 个小节相遇的地方有一些重叠像素。此外,圆的直径错误(应该始终为偶数,因为半径 * 2)是部分重叠的原因。

为了固定大小并移除重叠,我将半个圆圈向外(向右下方)移动了一个像素,并阻止渲染最后一次迭代像素的一半。

也不需要声明 if(err <= 0),因为此时 err 将始终满足该条件。 y 偏移每次迭代增加 1 个像素,err 用于查找 x 何时需要增加。

简单的解决方案

这样就解决了你关于在圆上打洞的问题。您只需要一个计数器来计算要跳过的像素数。当该计数器 > 0 时,不要绘制任何像素。

我将它添加到下面的代码片段中作为第 4 个参数 hole。一个 int 是圆的顶部、底部、左侧和右侧的孔的一半大小。

因此,如果您想要一个 20 像素的孔,那么最后一个参数是 10。

见下图中右边的圆圈。

限制和极客的东西

请注意,孔的最大尺寸为sin(PI / 4) * radius,如果将其变大,则不会绘制任何像素。作为旁注,绘制的像素数(没有孔)约为 sin(PI / 4) * radius * 8 - 4,比周长少了近 10%。

答案的解决方案

void drawcircle(int x0, int y0, int radius, int hole) {
    int x = radius-1;
    int y = 0;
    int dx = 1;
    int dy = 1;
    int err = dx - (radius << 1);
    int x1 = x0 + 1;
    int y1 = x0 + 1;

    while (x >= y) {
        if(hole == 0){
            putpixel(x1 + x, y1 + y);
            putpixel(x0 - x, y0 - y);
            putpixel(x0 - y, y1 + x);
            putpixel(x1 + x, y0 - y);
            if (x > y) {
                putpixel(x1 + y, y1 + x);                
                putpixel(x0 - x, y1 + y);                
                putpixel(x0 - y, y0 - x);
                putpixel(x1 + y, y0 - x);
            }
        } else {
            hole--;
        }

        y++;
        err += dy;
        dy += 2;

        if (err > 0) {
            x--;
            dx += 2;
            err += (-radius << 1) + dx;
        }
    }
}

此外,当我对这个功能非常感兴趣时,因为它制作了一些很好的高性能形状,如圆形十字形和盒子,只有非常小的变化,我认为值得分享。见图

要获得其他形状...

加回 y err 测试然后改变 delta X,delta y error 改为 2 以外的值。

        if(err <= 0){  // needed
            y++;
            err += dy;
            dy += 8;  << change this
        }

        if (err > 0) {
            x--;
            dx += 8;  << change this
            err += (-radius << 1) + dx;
        }
        // See image in answer
        // 8 made bottom right cross, 
        // 18 top right
        // 28 top left
        // 0.8 bottom left

图像显示孔的形状和结果