ビットマップの2つのポイント間に直線をどのように描画しますか?


17

私は高さマップ(ビットマップ)をいじって、自分のゲームで独自のマップを作成しようとしています。そのために、いくつかの基本的な描画メソッドを実装する必要があります。私はすぐに、直線を描くことは思ったほど基本的ではないことに気付きました。

ポイントがX座標またはY座標を共有している場合、または完全に対角線を描くことができるように位置が揃っている場合、それは簡単です。しかし、他のすべての場合では、より複雑です。

「まっすぐな」線になるためにどのピクセルに色を付ける必要があるかを決定するために、どのアルゴリズムを使用しますか?

回答:



21

Bresenhamのラインアルゴリズムを使用して、ラスターグリッド内のどのポイントをプロットするかを決定して、ラインセグメントを適切に視覚的に近似することができます。

このアルゴリズムは、原点が左上にある座標空間の原点と端点によって定義された線のラスタライズをカバーします。整数座標は、ピクセルの中心にマッピングされると推定されます。特に、アルゴリズムの基本形式は円の1オクタントのみをカバーします。X座標とY座標は増加しますが、絶対値が1未満の負の勾配を持つ曲線です。他のすべてのオクタントは、基本オクタント。

擬似コードでは、この基本フォームは次のようになります。

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のWebサイトには、さまざまな言語での具体的な実装のコレクションがあります

また、アンチエイリアスを可能にするWuのラインアルゴリズムにも興味があるかもしれません。


3
含まれている擬似コードをそのまま使用しないように、通行人に警告したいだけです。特定のオクタントでのみ機能します(答えの残りを読んでください)。コピー/貼り付けするコードを探している場合は、Rosetta Code Webサイトへのリンクを試してください。
コンガスボンガス14年

1
ウーのラインアルゴリズムのcバージョンをチェックアウトしたい人のために、それが不完全であることを警告したいと思います。_dla_changebrightnessでは、明るさを変更するときto->red = br * (float)from->red;に、次のように変更する必要がありますto->red = (br * (float)from->red) + ((1-br) * (float) to->red);。緑と青についても同じように敬意を表して
フレドリックボストンウェストマン14年

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;
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.