Dört Ağaçta Şekiller (Dikdörtgenler) Nasıl Çalışır?


10

Dört ağacın oyunum için ideal veri yapısı olduğu söylendi, ancak dört ağaçta şekillerin tam olarak nasıl çalıştığını anlamakta zorlanıyorum.

Bunu JavaScript ile yapıyorum, ancak bu soruların herhangi bir dilde dört ağaç için geçerli olabileceğini düşünüyorum.

Çoğunlukla dört ağaçlarda temel (x, y) noktaların ve nokta eklemenin nasıl çalıştığını ve kağıt üzerinde yapabileceğimi anlıyorum.

Puanlarla denemelerimin bir JSfiddle'ı .

dört ağaç noktaları

Bir vaka dışında, puanlı testlerim beklendiği gibi çalışıyor.

Ancak karışıklığım, dikdörtgen gibi şekiller söz konusu olduğunda başlar. Şekillerle dörtlü bir ağaçtan alırken, şeklin her noktasını ve hangi düğümlere düştüğünü kontrol ediyor mu? Şekil eklemeleri, her şekil için (x, y, genişlik, yükseklik) parametrelerini kabul ettiğinde nasıl çalışır? Daha sonra uygun düğümlere dağıtılan diğer köşe noktalarını hesaplamak için başlangıç ​​noktasından itibaren genişliği / yüksekliği kullanıyor mu? Eklenen bir şekil dört düğüme yayılıyorsa, bu şeklin verileri dört düğüme de kaydediliyor mu?

Ve bir alma yöntemi bir şekli parametre olarak kabul ettiğinde (x, y, genişlik, yükseklik), gerçekte neler oluyor? İlk olarak, şeklin eklenecekse hangi düğümlere yayılacağını görmek mi, daha sonra bu düğümlerin tüm nesnelerini almak mı?

Şekillerle çalışan bir JSfiddle'ım var , ancak testimin sonuçları hakkında tamamen kafam karıştı. Yinelenen nesneleri döndürülüyor alıyorum!

dört ağaç şekiller

Örneğin kırmızı kare, alma yöntemime girdiğim parametrelerin çizilmiş bir eşdeğeri. Bu kırmızı kare dört düğüme de yayıldığından, dört ağaçtaki her nesneyi döndürmesi gerektiğini düşünürüm! Ama olmuyor ve geri döndüklerini rasyonelleştirmekte zorlanıyorum. Şu anda yorum yapılan bir dizi başka testim var, ancak yorum ekleyebilir ve daha kafa karıştırıcı sonuçlar görmek için bunları çalıştırabilirsiniz!

Diyelim ki, dörtlü bir ağaçtaki tüm noktaları geri döndürmek istersem, bunu nasıl yaparım? Sınırların tüm boyutunu bir şekil kullanarak bir alma yöntemi? Örneğin, geri al (0, 0, canvas.width, canvas.height)?

Kullandığım JavaScript QuadTree kütüphanesine diğer çeşitli kaynaklar tarafından atıfta bulunuldu, bu yüzden gerçek uygulamanın doğru ve saygın olduğunu varsayıyorum.

Sanırım karışıklığımın çoğu dört ağaç terminolojisinin yanlış anlaşılmasından kaynaklanabilir. Bir "nokta" da genişlik / yükseklik parametrelerine sahip olduğunda neden boyutlar yerine sınırlar diyorlar? Bu bir konvansiyon / kısa el midir, yoksa tamamen farklı kavramlar mıdır?

Zaman ayırdığınız için teşekkürler!


Dört ağaçta normal şekilde, konumlarına göre depolanırlar. Genellikle bunlar merkezdedir, ancak tanımladığınız gibi köşede olabilir. Sorunuz bunun bir kopyası olabilir: QuadTree: yalnızca noktaları mı yoksa bölgeleri mi saklıyorsunuz?
MichaelHouse

Bu soruyu okudum, ancak cevapları hala tam olarak anlamıyorum :(. "Bu, kapasiteyi aşsa bile (yeniden boyutlandırılabilir bir kap kullanın), onu tamamen içeren en küçük düğümde saklamalısınız." - O TAMAMEN içerdiği en küçük düğümü söylüyor, eğer nesne çok büyükse, bu düğüm genellikle yapraksız bir düğüm olmaz mıydı? Sadece diğer düğümlerden oluşan bir yukarı düğümde olduğu gibi mi? ben, çünkü bu içerdiği düğüm 1 yaprak ve içinde 4 küçük düğüm olacaktır anlamına gelir
user2736286

1
@ user2736286 Dörtlü lib koduna bakarsanız (çok uzun değil), dikdörtgen düğüm sınırlarından korunmaları için dikdörtgenleri daha üst düzey düğümlerde depoladığını görebilirsiniz. Koddaki _stuckChildrenalana referanslara bakın . Bunu, "sınırları olan öğeleri alma" örneğinde de görebilirsiniz - tıklattığınız düğümlerin kenarlarına çarpan düğümleri, kök düğüme kadar her zaman kırmızıya vurgular.
Nathan Reed

@ user2736286 Ayrıca, quadtree lib, sınırları olan öğeleri alırken bir hataya sahip gibi görünüyor - eğer bazı düğüm kenarlıklarını tutan bir sorgu rektini verirseniz, sorgunun dokunduğu düğümlerdeki tüm rektleri döndürmez. Düğüm kenarlarına yakın tıklatarak "sınırları olan öğeleri alma" da bunu kolayca görebilirsiniz.
Nathan Reed

@NathanReed Daha önce kodu anlamaya çalıştım, ancak kavramsal bir temel olmadan onu anlayacak kadar yetenekli değilim. John McDonald's sözde kodu sayesinde, şimdi dikdörtgenlerin düğümlere nasıl eklendiğini anlıyorum, ancak geri alımın nasıl çalıştığı konusunda hala net değilim. "Sınırları olan öğeleri alma" gelince - Ben düz örnek ile karışık. Mesela, en küçük düğümlerden birine temiz bir şekilde uyan bir rektöre tıkladığımda, neden bu düğüm dışındaki diğer tüm rektifler de vurgulanıyor?
user2736286

Yanıtlar:


10

Quadtrees genellikle dikdörtgenleri depolar ve alır. Nokta, genişlik ve yüksekliğin sıfır olduğu özel bir durumdur. Aşağıdaki mantık, kök düğümden başlayarak ağaçtaki yeni dikdörtgenleri bulmak için kullanılır:

void Store(Rectangle rect)
{
    if(I have children nodes)
    {
        bool storedInChild = false;
        foreach(Node childNode in nodes)
        {
            if(this rectangle fits entirely inside the childNode bounds)
            {
                childNode.Store(rect);   // Go deeper into the tree
                storedInChild = true;
                break;
            }
        }
        if(not storedInChild)
        {
            Add this rectangle to the current node
        }
    }
    else
    {
        Add this rectangle to the current node
    }
}

Dikdörtgenlerin herhangi bir derinlikte saklanabileceğini, yaprak dörtlü olması gerekmediğini unutmayın. Dikdörtgen sınırı kök düzeyinde tutarsa, kök dörtlü dikdörtgeni depolar.

Örneğin, kırmızı kare alma yöntemime girdiğim parametrelerin çizilmiş bir eşdeğeri. Bu kırmızı kare dört düğüme de yayıldığından, dört ağaçtaki her nesneyi döndürmesi gerektiğini düşünürüm! Ama olmuyor ve geri döndüklerini rasyonelleştirmekte zorlanıyorum.

Dört ağaç sorgulanırken, yalnızca sorgunun içerdiği dikdörtgenleri döndürür. Örneğin, kırmızı sorgu dikdörtgeni her alt dörtlü ile kesiştiği için 4 alt dörtlüün her birine daha ayrıntılı olarak bakılmaya zorlarsınız. Çocukların başka çocuğu olmadığı için, bu çocuk dörtlülerindeki dikdörtgenlerin her biri kırmızı dikdörtgenle karşılaştırılacaktır. Ağaçtaki dikdörtgenlerin hiçbiri kırmızı sorgu dikdörtgeniyle çarpışmadığından hiçbir şey döndürülmemelidir.

Sorgu alan (lar) ına kıyasla çok fazla nesneniz ve nesnelerin var olması için çok fazla alanınız olduğunda, quadtrees'in avantajlarını gerçekten görmeye başlıyorsunuz. Bu durumlarda, küçük bir sorgu alanı, dörtlü ağacın geniş parçalarını göz önüne alarak hızla ortadan kaldırabilir. Yalnızca sorgu dikdörtgeniyle kesişen dörtlülere daha ayrıntılı olarak bakılır.

DÜZENLE

Alım genellikle aşağıdaki gibi yapılır:

List<Rectangle> Query(Rectangle queryRect)
{
    List<Rectangle> results;
    foreach(Node childNode in children)
    {
        if(queryRect intersects with childNode bounds)
        {
            results += childNode.Query(queryRect);   // Dig deeper into the tree
        }
    }

    foreach(Rectangle I have stored in this quad)
    {
        if(queryRect intersects with rect)  // Your library doesn't do this
        {
            results += rect;
        }
    }

    return results;
}

Ancak kitaplığınızda, döndürdüğü dikdörtgenlerin sorguyla kesişip kesişmediğini kontrol etmiyor gibi görünüyor, bu yüzden bunu kendiniz eklemeniz gerekecek.


Kitaplığınıza daha ayrıntılı bir şekilde baktıktan sonra, kitaplığınız belirttiğiniz sorgu dikdörtgeni için olası tüm çarpışma adaylarının bir listesini döndürüyor . Gerçek bir çarpışma olup olmadığını görmek için sorgu dikdörtgeninizi her adayla karşılaştırmak sizin işiniz gibi görünüyor . Çoğu kütüphane bu son adımı sizin için yapar ve sadece sorgu alanı ile gerçek çarpışmaları döndürür. Yani, tek yapmanız gereken retrievelisteyi budamak için yönteminize bir mantık eklemek . Burada ne yaptığını biraz daha net görebilirsiniz: mikechambers.com/html5/javascript/QuadTree/examples/…
John McDonald

1
@ user2736286 Eğer almadıysanız, JohnMcDonald'ın yazdığı Sorgu ve Mağaza işlevlerindeki yinelemeyi not etmek önemlidir. Eğer o kısmı alamazsan çok mantıklı olmayacak. Her ikisi için de, her özyineleme ağacın derinliklerine, yani dallara ve son olarak yapraklara gider.
TASagent

Teşekkürler John, sözde kodun çok faydalı. "İf (queryRect, childNode sınırları ile kesişir)" dediğinizde, temel olarak queryRect sınırlar içinde - kısmen veya tamamen içeriyorsa ? Sadece% 100 net olmak istiyorum. Ayrıca, tartışılan "öğeyi sınırlara göre al" örneğinde, tıklamamın sonucuna ilişkin bir resim var. Pic Mavi nokta tıkladığım yer. Öyleyse neden sadece bu düğüm içindeki iki dikdörtgen vurgulanmıyor? Dikdörtgenler neden ondan uzakta vurgulanır? Beni gerçekten şaşırtan şey bu.
user2736286

Parça veya dolu. Eğer iki dokunuş ya da ikisinden biri tamamen diğeri tarafından kapsanıyorsa. Wiki'yi Quadtrees'te okumak istiyorsunuz , ancak resminizi çektim ve farklı çocuk sınırlarını temsil etmek için renk kodladım . Tüm mavi dikdörtgenler ilk çocuk dörtlü sınırları ile kesişiyor, sonra macenta bir katman daha derin ve yeşil bir katman daha derin. Kırmızı dikdörtgenler, tıklanan dörtlü ile kesişir. Kitaplığınız alt sınırlar üzerindeki tüm rektleri ve son alt dörtte bulunanları
John McDonald

Tamam, bu yüzden lib kaynak kodu üzerinden gitmek için elimden geleni yaptım ve nihayet stuckChildren davranışını anlıyorum ve benim pic tüm bu ekstra rect's sadece stuckChildren vardır. Başlangıçta, birden fazla düğüme yayılan herhangi bir rektin sadece her küçük düğüme verilerinin çoğaltılmasını ve eklenmesini düşündüm. Şimdi, stuckChildren'in yaydığı düğümlere eklenmediğini, ancak onu içeren bir düğümde kaldığını fark ettim, bu yüzden tüm ana düğümleri kontrol etmem gerekiyor ve sadece sorgu rektemi içeren en küçük düğümü değil. Pic için teşekkürler; şimdi çok daha mantıklı :)
user2736286 15:13
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.