如何在位图中的两个点之间绘制一条直线?


17

我正在玩高度图(位图),试图在我的游戏中创建自己的一些东西,为此,我需要实现一些基本的绘制方法。我很快意识到画直线并不像我想的那么基本。

简单的是,如果您的点共享X或Y坐标,或者它们已对齐,则可以绘制一条完美的对角线。但是在所有其他情况下,它都比较棘手。

您使用哪种算法确定需要对哪些像素进行着色才能使其成为“直线”?

Answers:



21

Bresenham的线算法可用于确定要绘制的栅格网格中的哪些点,以实现线段的适当视觉近似。

该算法涵盖了由坐标原点位于左上角的坐标空间中的原点和端点定义的线的栅格化。假定整数坐标映射到像素中心。值得注意的是,该算法的基本形式仅覆盖圆的一个八分圆:该线的X和Y坐标增加,但斜率的绝对值小于1。所有其他八分圆都可以通过对此的简单变换得出基本八分圆。

在psuedocode中,此基本形式如下:

void DrawLine(Point origin, Point endpoint, Bitmap surface) {
    deltaX = endpoint.X - origin.X
    deltaY = endpoint.Y - origin.Y
    error = 0

    // Note the below fails for completely vertical lines.
    deltaError = absoluteValue(deltaY / deltaX)

    Y = origin.Y
    for (X from origin.X to endpoint.X) {
        surface.PlotPixel(X, Y)
        error = error + deltaError 
        if (error >= 0.5) {
            ++Y;
            error -= 1.0
        }
    }
}

Rosetta Code网站提供了多种语言的具体实现集合

您可能也对Wu的line算法感兴趣,该算法允许抗锯齿。


3
只是想警告路人,不要将包含的伪代码移出上下文,因为它开箱即用。它仅适用于特定的八分圆(请阅读答案的其余部分)。如果您正在寻找要复制/粘贴的代码,请尝试链接到Rosetta Code网站。
congusbongus

1
对于任何想了解Wu语言算法的C版本的人,我想警告您它不完整。在_dla_changebrightness中,当您更改亮度时,需要将其从:更改to->red = br * (float)from->red;为以下内容:to->red = (br * (float)from->red) + ((1-br) * (float) to->red);。执行相同的绿色和蓝色respectivly
弗雷德里克波士顿西人

2

这是画线的一种非常简单的方法。可以轻松更改该功能以在项目中使用。

void draw_line(float x0, float y0, const float& x1, const float& y1)
{
    float x{x1 - x0}, y{y1 - y0};
    const float max{std::max(std::fabs(x), std::fabs(y))};
    x /= max; y /= max;
    for (float n{0}; n < max; ++n)
    {
        // draw pixel at ( x0, y0 )
        x0 += x; y0 += y;
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.