すべてのタイルをループしたりスキップしたりせずに、線が交差しているタイルを見つける


10

私はこの問題を数日間見つめてきました。問題を視覚化するのに役立つように、このグラフィックを作りました:( ここに画像の説明を入力してください グラフから、線が[1、1]、[1、2]、[2、2]、[2、3]と交差し、[で終わることがわかります3,3])

ラインに沿って各グリッドスペースに進み、グリッドスペースのマテリアルが固体であるかどうかを確認したいと思います。関係する数学はすでに知っているように感じますが、まだまとめることはできていません。私はこれを使用して視線をテストし、パスファインディングアルゴリズムを介してパスが見つかった後にノードを排除します-エージェントは固体ブロックを通過できないため、ブロックを通過できず、ノードがパスから排除されません。コーナーをナビゲートするために必要です。

そのため、交差する各グリッドスペースまでラインに沿って進むアルゴリズムが必要です。何か案は?

私は、Bresenhamのような多くの一般的なアルゴリズムと、線に沿って事前定義された間隔でステップを実行するアルゴリズムを調べました(残念ながら、このメソッドは、タイルがステップサイズよりも小さいウェッジと交差している場合、タイルをスキップします)。

ホワイトボードに大量のfloor()関数とceil()関数を実装していますが、複雑すぎて、速度低下の原因となる可能性があります。


あなたは実際のラインボックス交差をテストする方法をすでに知っていますよね?ただ尋ねるだけで、これは答えに関連しています。
TravisG

回答:


6

開始ブロックがわかっている場合(ポイントXを知っていて、ブロックリストにブロック[0,1]を含めないので、開始ブロックも知っていると思います)、きっとBresenhamのアルゴリズムを使用する必要があると思います。あなたが書いた、それを見た。

これは、この問題に適したアルゴリズムです。それはある方法で書くこともでき、整数のみで計算します。あなたはウェブ上でそこに多くの実装を見つけることができます。

編集:

申し訳ありませんが、ブレゼンハムがすべてのブロックを見つけられないことに気づきませんでした。だから私はより良い解決策を見つけました。C ++で書かれたコードもありますが、理解するのは難しくないと思います:)


1
私がブレゼンハムのアルゴリズムを過ぎて見た理由は、純粋にウィキペディアの画像のためでした。(en.wikipedia.org/wiki/File:Bresenham.svg)線は、かろうじてではありますが、陰影のない四角形の一部を遮っていることがわかります。スライスがどれほど小さいかに関係なく、すべてのタイルを検出できるものが必要です。編集:とにかく私はブレゼンハムを誤解しているようです。私はそれを逆にする必要があります-最初と最後のポイントがあり、それが交差するタイルが必要です-プロットするのに最適なラインではありません。
Suds

@JustSuds:投稿の更新を確認します。
zacharmarz

ねえねえ!ホワイトボードにあるものとほぼ同じです!おかげで、私のシステムは実装され、動作しています。:-)
Suds

質問に答えないので、ブレゼンハムのアルゴリズムに関する部分を削除できますか?心配しないでください。回答の編集履歴に残ります。
天頂

1

受け入れられた回答がリンクする例のコードでは、完全に対角線を調整する必要があります。以下は、Qt(C ++およびQML)で記述された完全なデモアプリケーションです。

グリッドラインの交差

関連するC ++コード:

void rayCast()
{
    if (!isComponentComplete())
        return;

    mTiles.clear();
    mTiles.fill(QColor::fromRgb(255, 222, 173), mSizeInTiles.width() * mSizeInTiles.height());

    const QPoint startTile = startTilePos();
    const QPoint endTile = endTilePos();
    // http://playtechs.blogspot.com/2007/03/raytracing-on-grid.html
    int x0 = startTile.x();
    int y0 = startTile.y();
    int x1 = endTile.x();
    int y1 = endTile.y();

    int dx = abs(x1 - x0);
    int dy = abs(y1 - y0);
    int x = x0;
    int y = y0;
    int n = 1 + dx + dy;
    int x_inc = (x1 > x0) ? 1 : -1;
    int y_inc = (y1 > y0) ? 1 : -1;
    int error = dx - dy;
    dx *= 2;
    dy *= 2;

    for (; n > 0; --n)
    {
        visit(x, y);

        if (error > 0)
        {
            x += x_inc;
            error -= dy;
        }
        else if (error < 0)
        {
            y += y_inc;
            error += dx;
        }
        else if (error == 0) {
            // Ensure that perfectly diagonal lines don't take up more tiles than necessary.
            // http://playtechs.blogspot.com/2007/03/raytracing-on-grid.html?showComment=1281448902099#c3785285092830049685
            x += x_inc;
            y += y_inc;
            error -= dy;
            error += dx;
            --n;
        }
    }

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