Hangi döşemelerin bir çizgi ile kesiştiğini bulma, hepsini döngüye sokmadan veya herhangi birini atlamadan


10

Birkaç gündür bu soruna bakıyorum. Sorunu görselleştirmeme yardımcı olmak için bu grafiği hazırladım: resim açıklamasını buraya girin (grafikten, çizginin [1, 1], [1, 2], [2, 2], [2, 3] ile kesiştiğini, [ 3.3])

Her ızgara boşluğuna doğru ilerlemek ve ızgara boşluğunun malzemesinin sağlam olup olmadığını kontrol etmek istiyorum. Söz konusu matematiği zaten biliyormuşum gibi hissediyorum, ama henüz bir araya getiremedim. Bu benim görüş hattı test etmek ve benim yol bulma algoritmaları aracılığıyla bir yol bulunduktan sonra düğümleri ortadan kaldırmak için kullanıyorum - benim ajanlar katı bir blok üzerinden göremiyorum, bu nedenle onlar bir hareket edemez, bu nedenle düğüm yoldan elimine değil bir köşede gezinmek için gereklidir.

Yani, kesiştiği her ızgara alanına çizgi boyunca adım atacak bir algoritmaya ihtiyacım var. Herhangi bir fikir?

Bresenham'ın ve çizgi boyunca önceden tanımlanmış aralıklarla adım atan birçok ortak algoritmaya bir göz attım (ne yazık ki, bu yöntem adım boyutundan daha küçük bir kama ile kesişiyorsa fayansları atlıyor).

Beyaz tahtamı şimdi bir zemin () ve tavan () işlevleri kütlesi ile dolduruyorum - ama aşırı derecede karmaşıklaşıyor ve korkarım yavaşlamaya neden olabilir.


Gerçek hat kutusu kavşağını nasıl test edeceğinizi zaten biliyorsunuz, değil mi? Sadece sormak, çünkü bunun cevapla alakalı olması.
TravisG

olası yinelenen ben kayan nokta uç noktalara bresenham'ın çizgi algoritması genelleme nasıl? (soru aslında Bresenham ile ilgili değildir)
sam hocevar

Yanıtlar:


6

Başlangıç ​​bloğunu biliyorsanız (X noktasını biliyorsunuz ve blok listesine [0,1] bloğunu eklemiyorsunuz, bu yüzden başlangıç ​​bloğunu da bildiğinizi düşünüyorum), bresenham'ın algoritmasını mutlaka kullanmanız gerektiğini düşünüyorum. Sen yazdın, ona baktın.

Bu sorun için uygun bir algoritma. Ayrıca bir şekilde yazılabilir, sadece tamsayılarla hesaplar. Web üzerinde birçok uygulama bulabilirsiniz.

DÜZENLE:

Üzgünüm, Bresenham'ın tüm blokları bulamayacağını fark etmedim. Böylece daha iyi bir çözüm buldum . Ayrıca kod C ++ ile yazılmış, ama ben anlamak zor olmamalı düşünüyorum :)


1
Bresenham algoritmasını geçmemizin nedeni tamamen Wikipedia'daki görüntüden kaynaklanıyordu. ( en.wikipedia.org/wiki/File:Bresenham.svg ) Çizginin zar zor da olsa gölgesiz bazı kareleri kesdiğini görebilirsiniz. Dilimin ne kadar küçük olursa olsun, her döşemeyi algılayacak bir şeye ihtiyacım var. Edit: Görünüşe göre bresenham's zaten yanlış anladım. Bunu tersine çevirmem gerekiyor - ilk ve son noktaya sahibim ve kesiştiği karolara ihtiyacım var - çizmek için en iyi çizgi yerine.
Suds

@JustSuds: Yayındaki güncellemeyi kontrol edin.
zacharmarz

Hey hey! neredeyse beyaz tahtamda olanlarla neredeyse aynı! Teşekkürler, sistemim şimdi uygulandı ve çalışıyor. :-)
Suds

Soruyu cevaplamadığı için Bresenham'ın algoritması ile ilgili kısmı kaldırabilir misiniz? Endişelenme, yanıtınızın düzenleme geçmişinde kalacak.
zenith

1

Kabul edilen yanıtın bağlandığı örnekteki kod, mükemmel çapraz çizgiler için bazı ayarlamalar gerektirmektedir. İşte Qt (C ++ ve QML) ile yazılmış eksiksiz bir demo uygulaması.

ızgara çizgisi kesişimi

İlgili C ++ kodu:

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();
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.