Визначення того, які плитки перетинаються лінією, не перебираючи їх усіх і не пропускаючи жодної


10

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

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

Отже, мені потрібен алгоритм, який буде крокувати по лінії до кожного простору сітки, який він перетинає. Будь-які ідеї?

Я переглянув безліч поширених алгоритмів, таких як Брезенхем, і той, який крокує заздалегідь заданими інтервалами по лінії (на жаль, цей метод пропускає плитки, якщо вони перетинаються з меншим клином, ніж розмір кроку).

Зараз я заповнюю свою дошку масою функцій підлоги () та стелі () - але це стає надто складним, і я боюся, що це може спричинити уповільнення.


Ви вже знаєте, як перевірити фактичне перехрестя лінійної коробки, правда? Тільки запитаючи, чому це стосується відповіді.
TravisG

Відповіді:


6

Якщо ви знаєте стартовий блок (ви знаєте точку X, і ви не включаєте блок [0,1] у список блоків, тому, гадаю, ви знаєте також стартовий блок), я думаю, вам неодмінно слід використовувати алгоритм Брезена. Ти писав, ти на це дивився.

Для цієї проблеми підходить алгоритм. Він також може бути записаний таким чином, він обчислює лише цілі числа. Ви можете знайти багато реалізацій там в Інтернеті.

Редагувати:

Вибачте, я не зрозумів, що Бресенхем не знайде всіх блоків. Тож я знайшов краще рішення . Існує також код, написаний на C ++, але я думаю, це не повинно бути важко зрозуміти :)


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

@JustSuds: Перевірте наявність оновлень у пості.
zacharmarz

Гей-ей! що майже безпосередньо відповідає тому, що я маю на своїй дошці! Дякую, моя система зараз впроваджена та працює. :-)
Суди

Чи можете ви видалити частину алгоритму Брезена, оскільки вона не відповідає на питання? Не хвилюйтесь, це залишиться в історії редагування вашої відповіді.
зеніт

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.