C++ 在C+中从中心按像素绘制填充圆+;?

C++ 在C+中从中心按像素绘制填充圆+;?,c++,algorithm,plot,graphics,rasterizing,C++,Algorithm,Plot,Graphics,Rasterizing,我想从圆心开始逐行(如顺时针方向)逐像素地画圆。但是避免重画像素(这很慢) 想象一下,这就像“雷达”,每转一圈只更新一次 没有RAM来保存所有填充像素的数组(以前的最大线点),也没有GPU或高级库(按函数DrawPoint(x,y)绘制) 我有画线和点的功能: void DrawLineFromCenterXYToAngle(int centerX, int centerY, float angle) { .... instead of angle it is possible to find

我想从圆心开始逐行(如顺时针方向)逐像素地画圆。但是避免重画像素(这很慢)

想象一下,这就像“雷达”,每转一圈只更新一次

没有RAM来保存所有填充像素的数组(以前的最大线点),也没有GPU或高级库(按函数DrawPoint(x,y)绘制)

我有画线和点的功能:

void DrawLineFromCenterXYToAngle(int centerX, int centerY, float angle)
{
 .... instead of angle it is possible to find points of the circle and iterate it
 .... find line points by Bresenham's line algorithm
 {
  DrawPoint(int x, int y);
 }
}

void DrawPoint(int x, int y)
{
  PixelDraw_Slow(x,y)=GetColor_VerySlow(x,y);  
}
现在我迭代角度,非常缓慢地得到圆,因为中心的像素被多次重画。需要优化


如果这样做可以使形状更快,则形状可能不是完美的圆。

有用于圆的Bresenham绘图算法

intr=200,ymax,x,y,yp,xp,d;
ymax=r/sqrt(2);
x=r;/*从第一个八度音的底部开始*/
/*d测量两个像素位置的中点
在理想圆的内部或外部。积极意味着外部*/
d=-1*r;/*准确地说,这应该是r^2-(r-0.5)^2*/
xp=r;yp=-1;/*它们在迭代中保存旧值*/
对于(y=0;y0){/*中点在圆外,向西北方向移动*/
x--;
d+=(2*yp-2*xp+3);
}
否则{/*中点在圆内,转到N*/
d+=(2*yp+1);
}
yp=y;
xp=x;
}

有一种用于圆的Bresenham绘制算法

intr=200,ymax,x,y,yp,xp,d;
ymax=r/sqrt(2);
x=r;/*从第一个八度音的底部开始*/
/*d测量两个像素位置的中点
在理想圆的内部或外部。积极意味着外部*/
d=-1*r;/*准确地说,这应该是r^2-(r-0.5)^2*/
xp=r;yp=-1;/*它们在迭代中保存旧值*/
对于(y=0;y0){/*中点在圆外,向西北方向移动*/
x--;
d+=(2*yp-2*xp+3);
}
否则{/*中点在圆内,转到N*/
d+=(2*yp+1);
}
yp=y;
xp=x;
}
没有RAM来保存所有填充像素的数组(以前的最大线点),也没有GPU或高级库(按函数DrawPoint(x,y)绘制)

如果您可以存储一行点,那么您就有足够的内存来跟踪所有填充的像素,如果您有效地表示它的话

假设雷达扫描从12点钟或6点钟位置开始(顺时针或逆时针扫描无关紧要),则在渲染圆期间的任何时间,垂直线将只与填充像素块相交一次(即,输入一次,退出一次)。因此,只需存储每列像素的垂直最小和最大填充像素y坐标,就可以跟踪它们。如果从3点钟或9点钟位置开始,则可以存储每行的最小值和最大值x

只需使用几个阵列即可:

int minY[X_RANGE];
int maxY[X_RANGE];
X_RANGE是像素的最大列数。这只需要与圆一样大,而不是整个屏幕,因为可以基于圆边界框的左X偏移它。同样,Y_RANGE是最大行数

开始渲染时,初始化数组以表示空列:

void InitColumnArrays()
{
    for(int x = 0; x < X_RANGE; x++)
    {
        minY[x] = Y_RANGE - 1;
        maxY[x] = 0;
    }
}
void initColumnArray()
{
对于(int x=0;x
然后,在渲染像素时,只需通过检查阵列来检查它是否已被渲染:

void DrawPointCheckingRanges(int x, int y)
{
    // TODO: range check values

    // check if point has already been drawn and draw it and extend ranges if not:
    if((y < minY[x]) || (y > maxY[x]))
    {
        DrawPoint(x + offsetX, y + offsetX); 
        if(y < minY[x])
            minY[x] = y;
        if(y > maxY[x])
            maxY[x] = y;
    }
}
void DrawPointCheckingRanges(整数x,整数y)
{
//TODO:范围检查值
//检查是否已绘制点,如果未绘制点,则绘制点并扩展范围:
if((ymaxY[x]))
{
支点(x+偏移x,y+偏移x);
如果(ymaxY[x])
maxY[x]=y;
}
}
offsetX和offsetY是上面讨论的可选偏移

您可以将其与另一个答案中的Bresenham圆绘制算法结合使用,这将有效地为您提供直线的端点

上面的代码假设,与这些边界检查和数组读写相比,DrawPoint速度较慢

没有RAM来保存所有填充像素的数组(以前的最大线点),也没有GPU或高级库(按函数DrawPoint(x,y)绘制)

如果您可以存储一行点,那么您就有足够的内存来跟踪所有填充的像素,如果您有效地表示它的话

假设雷达扫描从12点钟或6点钟位置开始(顺时针或逆时针扫描无关紧要),则在渲染圆期间的任何时间,垂直线将只与填充像素块相交一次(即,输入一次,退出一次)。因此,只需存储每列像素的垂直最小和最大填充像素y坐标,就可以跟踪它们。如果从3点钟或9点钟位置开始,则可以存储每行的最小值和最大值x

只需使用几个阵列即可:

int minY[X_RANGE];
int maxY[X_RANGE];
X_RANGE是像素的最大列数。这只需要与圆一样大,而不是整个屏幕,因为可以基于圆边界框的左X偏移它。同样,Y_RANGE是最大行数

开始渲染时,初始化数组以表示空列:

void InitColumnArrays()
{
    for(int x = 0; x < X_RANGE; x++)
    {
        minY[x] = Y_RANGE - 1;
        maxY[x] = 0;
    }
}
void initColumnArray()
{
对于(int x=0;x
然后,在渲染像素时,只需通过检查阵列来检查它是否已被渲染:

void DrawPointCheckingRanges(int x, int y)
{
    // TODO: range check values

    // check if point has already been drawn and draw it and extend ranges if not:
    if((y < minY[x]) || (y > maxY[x]))
    {
        DrawPoint(x + offsetX, y + offsetX); 
        if(y < minY[x])
            minY[x] = y;
        if(y > maxY[x])
            maxY[x] = y;
    }
}
void DrawPointCheckingRanges(整数x,整数y)
{
//TODO:范围检查值
//检查是否已绘制点,如果未绘制点,则绘制点并扩展范围:
if((ymaxY[x]))
{
支点(x+偏移x,y+偏移x);
如果(ymaxY[x])
maxY[x]=y;
}
}