You have a nice solution (an item->node index) for dealing with the usual problem with update methods that arises from the need to remove with the old bounding box and insert with the new bounding box.
The insert method is O(ln(N)) but an update where the item stays in the same node could be accomplished in constant time. Moving to a child node could also be optimized by removing the search down to the node currently holding the item, and moving to adjacent nodes could also eliminate some of this search because each node knows its parent.
I don't know Lua, so please treat the code below as pseudo-code.
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
I'm not sure that it is worth scanning up the tree as well as down. It might be interesting to try, but it is only likely to be worth it in a very deep tree.
The findNode method scans the tree from self looking for the node that the item belongs to by spatial location. Implementations can choose to scan only the self node and its dependents:
-- 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
... or to scan the whole tree using parent nodes as well:
-- 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