Trovare quali tessere sono intersecate da una linea, senza passare attraverso tutte o saltare


10

Sto fissando questo problema da alcuni giorni. Ho truccato questo grafico per aiutarmi a visualizzare il problema: inserisci qui la descrizione dell'immagine (dal grafico, sappiamo che la linea interseca [1, 1], [1, 2], [2, 2], [2, 3], che termina in [ 3,3])

Voglio avanzare lungo la linea per ogni spazio della griglia e verificare se il materiale dello spazio della griglia è solido. Mi sembra di conoscere già la matematica coinvolta, ma non sono ancora riuscito a metterla insieme. Lo sto usando per testare la linea di vista ed eliminare i nodi dopo che è stato trovato un percorso tramite i miei algoritmi di pathfinding: i miei agenti non possono vedere attraverso un blocco solido, quindi non possono spostarsi attraverso uno, quindi il nodo non viene eliminato dal percorso perché è necessario per navigare in un angolo.

Quindi, ho bisogno di un algoritmo che passi lungo la linea per ogni spazio della griglia che interseca. Qualche idea?

Ho dato un'occhiata a molti algoritmi comuni, come quello di Bresenham, e uno che fa passi a intervalli predefiniti lungo la linea (sfortunatamente, questo metodo salta le piastrelle se si intersecano con un cuneo più piccolo della dimensione del passo).

Sto popolando la mia lavagna ora con una massa di funzioni floor () e ceil () - ma sta diventando eccessivamente complicata e temo che potrebbe causare un rallentamento.


Sai già come testare l'intersezione di line-box, giusto? Basta chiedere, perché questo è rilevante per la risposta.
TravisG,

possibile duplicato di Come generalizzare l'algoritmo di linea di Bresenham su endpoint a virgola mobile? (la domanda in realtà non riguarda Bresenham)
sam hocevar,

Risposte:


6

Se conosci il blocco iniziale (conosci il punto X e non includi il blocco [0,1] nella lista dei blocchi, quindi suppongo che tu conosca anche il blocco iniziale), penso che dovresti sicuramente usare l'algoritmo di Bresenham. Hai scritto, l'hai guardato.

È un algoritmo adatto a questo problema. Può anche essere scritto in un modo, calcola solo con numeri interi. Puoi trovare molte implementazioni sul Web.

MODIFICARE:

Mi dispiace, non mi sono reso conto che Bresenham non troverà tutti i blocchi. Quindi ho trovato una soluzione migliore . C'è anche un codice scritto in C ++, ma penso che non dovrebbe essere difficile da capire :)


1
Il motivo per cui ho guardato oltre l'algoritmo di Bresenham era semplicemente dovuto all'immagine su Wikipedia. ( en.wikipedia.org/wiki/File:Bresenham.svg ) Puoi vedere che la linea intercetta alcuni quadrati non ombreggiati, anche se a malapena. Ho bisogno di qualcosa che rilevi ogni tessera, indipendentemente da quanto sia infinitamente piccola la fetta. Modifica: Sembra che io abbia frainteso comunque quello di Bresenham. Devo invertirlo - ho il primo e l'ultimo punto e ho bisogno delle tessere che interseca - piuttosto che della linea che sarebbe meglio tracciare.
Suds,

@JustSuds: controlla l'aggiornamento per posta.
Zacharmarz,

Ehi ehi! che corrisponde quasi direttamente a quello che ho sulla mia lavagna! Grazie, il mio sistema è ora implementato e funzionante. :-)
Suds,

Riesci a rimuovere la parte relativa all'algoritmo di Bresenham in quanto non risponde alla domanda? Non preoccuparti, rimarrà nella cronologia delle modifiche della tua risposta.
Zenith,

1

Il codice nell'esempio a cui si collega la risposta accettata necessita di alcune regolazioni per linee perfettamente diagonali. Ecco un'applicazione demo completa scritta con Qt (C ++ e QML).

intersezione della linea della griglia

Codice C ++ pertinente:

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();
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.