Нахождение, какие плитки пересекаются линией, без циклического прохождения всех их или пропуская любые


10

Я смотрю на эту проблему уже несколько дней. Я установил этот график, чтобы помочь мне визуализировать проблему: введите описание изображения здесь (из графика мы знаем, что линия пересекает [1, 1], [1, 2], [2, 2], [2, 3], заканчиваясь на [ 3,3])

Я хочу пройти по линии к каждому пространству сетки и проверить, является ли материал пространства сетки твердым. Я чувствую, что уже знаю, как работает математика, но я пока не смог ее связать. Я использую это для проверки прямой видимости и устранения узлов после того, как путь найден с помощью моих алгоритмов поиска пути - мои агенты не могут видеть сквозь сплошной блок, поэтому они не могут перемещаться через один, поэтому узел не исключается из пути, потому что он требуется для навигации по углу.

Итак, мне нужен алгоритм, который будет двигаться вдоль линии к каждому пространству сетки, которое он пересекает. Любые идеи?

Я рассмотрел множество распространенных алгоритмов, таких как алгоритм Брезенхэма, и алгоритм, который шагает с заранее заданными интервалами вдоль линии (к сожалению, этот метод пропускает плитки, если они пересекаются с меньшим клином, чем размер шага).

Сейчас я заполняю свою доску массой функций floor () и ceil (), но она становится слишком сложной, и я боюсь, что это может вызвать замедление.


Вы уже знаете, как проверить фактическое пересечение линейных блоков, верно? Просто спрашиваю, потому что это имеет отношение к ответу.
TravisG

Ответы:


6

Если вы знаете начальный блок (вы знаете точку X и вы не включили блок [0,1] в список блоков, поэтому, я полагаю, вы знаете также начальный блок), я думаю, что вы обязательно должны использовать алгоритм Брезенхэма. Вы написали, вы смотрели на это.

Это подходящий алгоритм для этой проблемы. Он также может быть записан таким образом, что он вычисляется только с целыми числами. Вы можете найти множество реализаций в сети.

РЕДАКТИРОВАТЬ:

Извините, я не понял, что Брезенхем не найдет все блоки. Поэтому я нашел лучшее решение . Есть также код, написанный на C ++, но я думаю, что это не должно быть трудно понять :)


1
Причина, по которой я посмотрел мимо алгоритма Брезенхема, была исключительно из-за изображения в Википедии. ( en.wikipedia.org/wiki/File:Bresenham.svg ) Вы можете видеть, что линия пересекает некоторые незатененные квадраты, хотя и едва. Мне нужно что-то, что будет определять каждую плитку, независимо от того, насколько бесконечно маленький срез. Изменить: Похоже, что я все равно неправильно понял Bresenham. Мне нужно повернуть вспять - у меня есть первая и последняя точка, и мне нужны плитки, которые она пересекает, - а не линия, которую лучше всего построить.
Суд

@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();
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.