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
图像显示孔的形状和结果
在我的程序中,我目前使用中点圆算法和以下代码渲染圆。
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
图像显示孔的形状和结果