c++ - 绘图圆,OpenGL 风格

标签 c++ c algorithm graphics embedded

我有一个 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/

相关文章:

c++ - 将 pfx 证书转换为 PEM 格式

c++ - 不同计算机之间的 C++ <随机> 行为不一致

algorithm - 使用定界符连接字符串

php - 网址缩短网站

c++ - QPieSlice的Qt坐标

c++ - 从命令行c++计算两个数字

javascript - Ruby MongoDB 驱动程序客户端查询匹配器

c - 将结构从 main() 传递到辅助函数时出现段错误

将字符串复制到数组中,然后使用 for 循环打印它

笔记本电脑触摸板上的触摸检测算法?