I am creating a quadtree for a 2D game in C# to make the rendering faster. Some of the objects (planets) are moving and that is why, I created a method called removeAndUpdate
to update the tree by deleting and reinserting the specific object from the leaves (so not from the root) as I have already read in link. Unfortunately, I got System.OutOfMemoryException
after some time at the reinsertion part. I am quite sure, that the removeAndUpdate
method has some problems.
Maybe it is good to mention, that when a quad is subdivided (in case, when the quad's storing capacity is full), the content will not distributed among the subquads. I made this way to improve some performance. However, I don't think it has some connection with the problem above.
I guess, there is an infinite loop somewhere, which causes to run out of memory. If I insert new objects from the root, there is no problem.
I wrote a comment to the place where the exception occurs.
Here you can see the important parts of the QuadTree class:
public class QuadTree
{
BoundingBox boundary;
int capacity;
List<WorldObject> leafContent;
public QuadTree parent;
bool divided;
public List<QuadTree> childQuadTrees;
public QuadTree(BoundingBox _boundary, int _capacity, QuadTree _parent)
{
this.boundary = _boundary;
this.capacity = _capacity;
this.leafContent = new List<WorldObject>();
this.childQuadTrees = new List<QuadTree>();
this.divided = false;
this.parent = _parent;
}
// Subdividing the quad, if its storing capacity is full.
public void subdivide()
{
// North-East
this.childQuadTrees.Add(new QuadTree(new BoundingBox(new Vector3(boundary.Center.X, 0, boundary.Min.Z),
new Vector3(boundary.Max.X, 0, boundary.Center.Z)), this.capacity, this));
// North-West
this.childQuadTrees.Add(new QuadTree(new BoundingBox(new Vector3(boundary.Min.X, 0, boundary.Min.Z),
new Vector3(boundary.Center.X, 0, boundary.Center.Z)), this.capacity, this));
// South-East
this.childQuadTrees.Add(new QuadTree(new BoundingBox(boundary.Center, boundary.Max), this.capacity, this));
// South-West
this.childQuadTrees.Add(new QuadTree(new BoundingBox(new Vector3(boundary.Min.X, 0, boundary.Center.Z), new Vector3(boundary.Center.X, 0, boundary.Max.Z)), this.capacity, this));
this.divided = true;
}
public void insert(WorldObject wO)
{
// Checking, whether the quad contains the box at all.
if (!this.ContainOrOverlap(wO.BoundingBox))
{
return;
}
// If there is space, insert the box.
if (this.leafContent.Count < this.capacity && this.divided == false)
{
/*This is the instruction, where System.OutOfMemoryException occures*/
this.leafContent.Add(wO); // <-------
return;
}
// If not, subdivide the quad then insert the obj to the subquads.
else
{
if (this.divided == false)
{
this.subdivide();
}
this.childQuadTrees[0].insert(wO);
this.childQuadTrees[1].insert(wO);
this.childQuadTrees[2].insert(wO);
this.childQuadTrees[3].insert(wO);
}
}
/* Here is the method to update the moving objects bounding volume.
It first removes the element from the tree, updates the boundingbox, then reinsert the object from the leaves*/
public void removeAndUpdate(WorldObject obj, Vector3 displacement)
{
if (!this.ContainOrOverlap(obj.BoundingBox))
{
return;
}
if (this.divided)
{
this.childQuadTrees[0].removeAndUpdate(obj, displacement);
this.childQuadTrees[1].removeAndUpdate(obj, displacement);
this.childQuadTrees[2].removeAndUpdate(obj, displacement);
this.childQuadTrees[3].removeAndUpdate(obj, displacement);
}
/* if the obj is found, remove it, the try to reinsert it to its parent. If its parent does not contain it, move upwards in the hierarchy and try again to insert*/
if (leafContent.Contains(obj))
{
this.leafContent.Remove(obj);
QuadTree q = this.parent;
while (q.ContainOrOverlap(obj.BoundingBox) == false)
{
q = q.parent;
}
obj.BoundingBox.Translate(displacement);
q.insert(obj);
}
}
public void query(BoundingBox range, List<WorldObject> resultList)
{
if (!this.ContainOrOverlap(range))
{
return;
}
if (this.divided)
{
this.childQuadTrees[0].query(range, resultList);
this.childQuadTrees[1].query(range, resultList);
this.childQuadTrees[2].query(range, resultList);
this.childQuadTrees[3].query(range, resultList);
}
resultList.AddList(this.leafContent);
}
}
Here is some info from the debug at the break of the exception: