查找哪些瓷砖与一条线相交,而无需遍历所有瓷砖或跳过任何瓷砖


10

我已经盯着这个问题几天了。我整理了此图形以帮助我直观地看到问题:( 在此处输入图片说明 从图形中我们知道线与[1,1],[1,2],[2,2],[2,3]相交,以[ 3,3])

我想沿着直线移动到每个网格空间,并检查网格空间的材质是否牢固。我觉得我已经知道所涉及的数学,但是我还不能将其组合在一起。我正在使用它来测试视线并在通过我的寻路算法找到路径后消除节点-我的代理无法看到实体块,因此它们无法通过实体,因此不会从路径中消除该节点,因为它需要导航一个角。

因此,我需要一种算法,该算法将沿着直线移动到它相交的每个网格空间。有任何想法吗?

我看了很多常见的算法,例如布雷森汉姆算法,以及沿着线以预定间隔步进的算法(不幸的是,如果它们与比步长小的楔形相交,则此方法会跳过这些图块)。

我现在用大量floor()和ceil()函数填充我的白板-但是它变得过于复杂,我担心它可能会导致速度变慢。


您已经知道如何测试实际的线盒交点,对吗?只是问,因为这与答案有关。
TravisG 2011年

Answers:


6

如果您知道起始块(您知道点X并且没有在块列表中包含块[0,1],那么我想您也知道起始块),我认为您肯定应该使用Bresenham算法。你写了,你看着它。

这是解决此问题的合适算法。它也可以以某种方式编写,它仅使用整数进行计算。您可以在网上找到许多实现。

编辑:

对不起,我还没有意识到布雷森纳姆不会找到所有街区。所以我找到了更好的解决方案。也有用C ++编写的代码,但我认为应该不难理解:)


1
我之所以忽略布雷森汉算法,是因为维基百科上的图片。(en.wikipedia.org/wiki/File:Bresenham.svg)您可以看到这条线截取了一些没有阴影的正方形,尽管几乎没有。无论切片有多小,我都需要能够检测每个切片的工具。编辑:看来我还是误解了布雷森汉姆。我需要反转它-我有第一个和最后一个点,我需要它相交的图块-而不是最好绘制的线。
肥皂水

@JustSuds:检查更新。
zacharmarz 2011年

嘿嘿!几乎与我在白板上的内容完全匹配!谢谢,我的系统现已实施并可以正常工作。:-)
Suds

您是否可以删除有关Bresenham算法的部分,因为它没有回答问题?不用担心,它将保留在您答案的编辑历史记录中。
天顶

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();
}
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.