我有一个 13 x 13 的像素阵列,我正在使用一个函数在它们上面画一个圆。 (屏幕是 13 * 13,这可能看起来很奇怪,但它是一个 LED 阵列,所以可以解释它。)
unsigned char matrix[13][13];
const unsigned char ON = 0x01;
const unsigned char OFF = 0x00;
这是我想到的第一个实现。 (它效率低下,这是一个特殊的问题,因为这是一个嵌入式系统项目,80 MHz 处理器。)
// Draw a circle
// mode is 'ON' or 'OFF'
inline void drawCircle(float rad, unsigned char mode)
{
for(int ix = 0; ix < 13; ++ ix)
{
for(int jx = 0; jx < 13; ++ jx)
{
float r; // Radial
float s; // Angular ("theta")
matrix_to_polar(ix, jx, &r, &s); // Converts polar coordinates
// specified by r and s, where
// s is the angle, to index coordinates
// specified by ix and jx.
// This function just converts to
// cartesian and then translates by 6.0.
if(r < rad)
{
matrix[ix][jx] = mode; // Turn pixel in matrix 'ON' or 'OFF'
}
}
}
}
我希望这很清楚。它非常简单,但后来我对它进行了编程,所以我知道它应该如何工作。如果您想要更多信息/解释,那么我可以添加更多代码/评论。
可以认为绘制多个圆圈(例如 4 到 6 个)非常慢......因此,我正在寻求有关更有效的算法来绘制圆圈的建议。
编辑:通过进行以下修改设法使性能翻倍:
调用绘图的函数以前看起来像这样:
for(;;)
{
clearAll(); // Clear matrix
for(int ix = 0; ix < 6; ++ ix)
{
rad[ix] += rad_incr_step;
drawRing(rad[ix], rad[ix] - rad_width);
}
if(rad[5] >= 7.0)
{
for(int ix = 0; ix < 6; ++ ix)
{
rad[ix] = rad_space_step * (float)(-ix);
}
}
writeAll(); // Write
}
我添加了以下检查:
if(rad[ix] - rad_width < 7.0)
drawRing(rad[ix], rad[ix] - rad_width);
这将性能提高了大约 2 倍,但理想情况下,我想让圆绘制更高效以进一步提高性能。这会检查环是否完全在屏幕之外。
编辑 2:类似地添加反向检查进一步提高了性能。
if(rad[ix] >= 0.0)
drawRing(rad[ix], rad[ix] - rad_width);
性能现在非常好,但我再次没有对圆圈的实际绘制代码进行任何修改,这就是我打算在这个问题上关注的问题。
编辑 3:矩阵到极坐标:
inline void matrix_to_polar(int i, int j, float* r, float* s)
{
float x, y;
matrix_to_cartesian(i, j, &x, &y);
calcPolar(x, y, r, s);
}
inline void matrix_to_cartesian(int i, int j, float* x, float* y)
{
*x = getX(i);
*y = getY(j);
}
inline void calcPolar(float x, float y, float* r, float* s)
{
*r = sqrt(x * x + y * y);
*s = atan2(y, x);
}
inline float getX(int xc)
{
return (float(xc) - 6.0);
}
inline float getY(int yc)
{
return (float(yc) - 6.0);
}
作为对 Clifford 的回应,如果它们不是内联的,实际上会有很多函数调用。
编辑 4:drawRing 只绘制 2 个圆,首先是一个模式为 ON 的外圆,然后是一个模式为 OFF 的内圆。我相当有信心也有一种更有效的方法来绘制这样的形状,但这会分散我们对问题的注意力。
最佳答案
您正在做很多实际上不需要的计算。例如,您正在计算极坐标的角度,但从不使用它。通过比较值的平方也可以轻松避免平方根。
无需做任何花哨的事情,这样的事情应该是一个好的开始:
int intRad = (int)rad;
int intRadSqr = (int)(rad * rad);
for (int ix = 0; ix <= intRad; ++ix)
{
for (int jx = 0; jx <= intRad; ++jx)
{
if (ix * ix + jx * jx <= radSqr)
{
matrix[6 - ix][6 - jx] = mode;
matrix[6 - ix][6 + jx] = mode;
matrix[6 + ix][6 - jx] = mode;
matrix[6 + ix][6 + jx] = mode;
}
}
}
这会以整数格式进行所有数学运算,并利用圆对称性。
以上内容的变体,基于评论中的反馈:
int intRad = (int)rad;
int intRadSqr = (int)(rad * rad);
for (int ix = 0; ix <= intRad; ++ix)
{
for (int jx = 0; ix * ix + jx * jx <= radSqr; ++jx)
{
matrix[6 - ix][6 - jx] = mode;
matrix[6 - ix][6 + jx] = mode;
matrix[6 + ix][6 - jx] = mode;
matrix[6 + ix][6 + jx] = mode;
}
}
关于c++ - 绘图圆,OpenGL 风格,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25573453/