在C ++中用中心像素绘制实心圆圈?

时间:2017-02-19 15:11:29

标签: 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 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);  
}

现在我迭代角度并且非常慢地得到圆圈,因为中心的像素重绘了很多次。并需要优化。

如果形状更快,形状可能不是完美的圆形。

2 个答案:

答案 0 :(得分:0)

圈子有Bresenham绘图算法。

Example with code

int r = 200, ymax, x, y, yp, xp, d;
ymax = r / sqrt(2);
x = r; /* start at the bottom of the first octant */
/* d measures whether the midpoint of two pixel locations
is inside or outside the ideal circle. positive means outside */
d = -1*r; /* to be precise, this should be r^2 - (r - 0.5)^2 */
xp = r; yp = -1; /* these hold the old values across iterations */
for(y=0; y<=ymax; y++) {
  plot_8_ways(x,y);
  if (d > 0) { /* midpoint is outside circle, go NW */
    x--;
    d += (2*yp - 2*xp + 3);
  }
  else { /* midpoint is inside circle, go N */
    d += (2*yp + 1);
  }
  yp = y;
  xp = x;
}

答案 1 :(得分:0)

  

没有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 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;
    }
}

offsetX和offsetY是可选偏移,如上所述。

您可以将其与其他答案中的Bresenham圆绘制算法结合使用,这将有效地为您的线提供终点。

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