2010-05-23 33 views
7

我已經實現了一個工作QuadTree。它細分二維空間以容納物品,通過它們的邊界框(x,y,寬度,高度)在儘可能最小的四邊形(達到最小面積)上標識。QuadTrees - 內部項目移動時如何更新

我的代碼是在此基礎上實現(我的是在Lua的C#代替):http://www.codeproject.com/KB/recipes/QuadTree.aspx

我已經能夠成功地實現插入和刪除。現在我已經把注意力轉向了update()函數,因爲我的物品的位置和尺寸隨時間而變化。

我的第一個執行工作,但它是相當幼稚的:

function QuadTree:update(item) 
    self:remove(item) 
    return self.root:insert(item) 
end 

是啊,我基本上撈出每次移動時重新插入每一個項目。

這有效,但我想優化一點;畢竟,大多數情況下,移動的項目仍然保留在同一個quadTree節點上。

是否有任何標準的方法來處理這種更新?

萬一有幫助,我的代碼是在這裏:https://github.com/kikito/middleclass-ai/blob/master/QuadTree.lua

我不會找人來實現它給我;指向現有工作實現(甚至用其他語言)的指針就足夠了。

回答

4

您有一個很好的解決方案(一個item-> node index)用於處理更新方法中的常見問題,這些更新方法源於需要使用舊邊界框刪除並使用新邊界框插入的問題。

插入方法是O(ln(N)),但項目停留在同一節點的更新可以在恆定時間內完成。移動到子節點也可以通過將搜索移除到當前持有該項目的節點來優化,並且移動到相鄰節點也可以消除一些此搜索,因爲每個節點都知道它的父節點。

我不知道Lua,所以請把下面的代碼視爲僞代碼。

function QuadTree:update(item) 
    oldNode = root.assignments[item] 
    newNode = oldNode:findNode(item) 

    if (oldNode ~= newNode) then 

     -- if findNode only searches down the tree newNode will be nil if 
     -- the item needs to move to/under an adjacent node. Otherwise the 
     -- next three lines are not needed 
     if (newNode == nil) then 
      newNode = root:findNode(item) 
     end 

     oldNode:remove(item) 
     newNode = newNode:insert(item) 
    end 

    return newNode 
end 

我不確定是否值得向上掃描樹。嘗試可能會很有趣,但只有在非常深的樹中才值得。

findNode方法通過自我掃描樹找到該項所屬的節點的空間位置。實現可以選擇只掃描自節點及其家屬:

-- Returns the node that the item belongs to by spatial location. 
-- The tree can already contain the item. The item might be indexed using 
-- an old geometry. 
-- This method does not create child nodes. 
function QuadTree:findNode(item) 
    local x,y,w,h = item:getBoundingBox() 
    if(not _contained(x,y,w,h , self:getBoundingBox())) then 
     -- Attempted to insert an item on a QuadTree that does not contain it; 
     -- just return 
     return nil 
    end 

    for _,node in ipairs(self.nodes) do 
     if(node:findNode(item) ~= nil) then return node end 
    end 

    return self 
end 

...或使用父節點,掃描整個樹:

-- Returns the node that the item belongs to by spatial location. 
-- The tree can already contain the item. The item might be indexed using 
-- an old geometry. 
-- This method does not create child nodes. 
function QuadTree:findNode(item) 
    local x,y,w,h = item:getBoundingBox() 
    if(not _contained(x,y,w,h , self:getBoundingBox())) then 
     -- Attempted to insert an item on a QuadTree that does not contain it; 
     -- scan the parent 
     if (parent == nil) then return nil end 

     return parent:findNode(item) 
    end 

    for _,node in ipairs(self.nodes) do 
     if(node:findNode(item) ~= nil) then return node end 
    end 

    return self 
end 
+0

謝謝回答。幾何圖形是在四叉樹外部更新的 - 項目本身負責這樣做。你的例子的問題是oldNode:contains() - 即使它包含該項目,也可能是新節點是oldNode的子節點之一;例如,如果項目較小。我在試圖建模時遇到困難。 – kikito 2010-05-23 11:13:53

+0

這是一個很好的觀點,我沒有說清楚:包含,移除和插入都可以是非遞歸實現,因爲它們正在處理的節點是正確的,即它們在Node上工作,而不是在Tree上工作沒有獨特的Node類。findNode必須在樹上遞歸地工作,它類似於插入,但沒有實際插入。 – richj 2010-05-23 11:22:13

+0

第二個想法是,如果findNode沒有分割完整的節點會更好,因爲不是所有的findNode調用都跟着插入。我更新了僞代碼以允許newNode.insert(item)返回newNode的子節點。 – richj 2010-05-23 11:41:13

相關問題