如何在 QuadTree 中的所有相交四边形中插入节点?
How to insert node in all intersecting quads in QuadTree?
我有一个四叉树,但插入方法无法正常工作。现在它只插入它看到的第一个相交四边形。目的是将所有节点插入与其相交的所有四边形中。例如:当一个节点在两个四边形的边界上时,它被插入到两个四边形中。有人可以帮助我将插入方法插入到所有相交四边形中吗?
这是我当前的实现:
这是插入节点的调用:
QuadTree = new QuadTreeNode < Artist > (new Rect(0, 0, Width, Height), 1);
foreach(Artist artist in Artists) {
QuadTree.Insert(artist);
}
这是我的四叉树class:
public interface WithRect {
Rect Rect {
get;
}
}
public class QuadTreeNode < T > where T: WithRect {
Rect bounds;
List < T > contents;
int numberOfNodesInserted = 0;
int max = 4;
int depth = 0;
int maxDepth = 6;
bool divided;
QuadTreeNode < T > TopLeft;
QuadTreeNode < T > TopRight;
QuadTreeNode < T > BottomLeft;
QuadTreeNode < T > BottomRight;
public QuadTreeNode(Rect _bounds, int _depth) {
depth = _depth;
bounds = _bounds;
contents = new List < T > ();
divided = false;
}
public void DivideQuad() {
int newDepth = depth + 1;
double x = bounds.X;
double y = bounds.Y;
double width = bounds.Width;
double height = bounds.Height;
TopLeft = new QuadTreeNode < T > (new Rect(x, y, width / 2, height / 2), newDepth);
TopRight = new QuadTreeNode < T > (new Rect(x + width / 2, y, width / 2, height / 2), newDepth);
BottomLeft = new QuadTreeNode < T > (new Rect(x, y + height / 2, width / 2, height / 2), newDepth);
BottomRight = new QuadTreeNode < T > (new Rect(x + width / 2, y + height / 2, width / 2, height / 2), newDepth);
divided = true;
foreach(T item in contents) {
Insert(item);
}
contents.Clear();
}
public bool Insert(T item) {
if (!bounds.IntersectsWith(item.Rect)) return false;
if (numberOfNodesInserted < max || depth == maxDepth) {
contents.Add(item);
numberOfNodesInserted++;
return true;
}
else {
if (!divided) {
DivideQuad();
}
if (TopLeft.Insert(item)) return true;
else if (TopRight.Insert(item)) return true;
else if (BottomLeft.Insert(item)) return true;
else if (BottomRight.Insert(item)) return true;
else return false;
}
}
public void GetBounds(ref List < Rect > results) {
if (bounds != null) results.Add(bounds);
if (TopLeft != null) TopLeft.GetBounds(ref results);
if (TopRight != null) TopRight.GetBounds(ref results);
if (BottomLeft != null) BottomLeft.GetBounds(ref results);
if (BottomRight != null) BottomRight.GetBounds(ref results);
}
public void Query(T item, ref List < T > collisions, List < Square > squares, int squareWidth, int squareHeight) {
if (item.Rect.IntersectsWith(bounds)) {
if (divided) {
TopLeft.Query(item, ref collisions, squares, squareWidth, squareHeight);
TopRight.Query(item, ref collisions, squares, squareWidth, squareHeight);
BottomLeft.Query(item, ref collisions, squares, squareWidth, squareHeight);
BottomRight.Query(item, ref collisions, squares, squareWidth, squareHeight);
}
for (int i = 0; i < contents.Count; i++) {
if (item.Rect != contents[i].Rect) {
if (item.Rect.IntersectsWith(contents[i].Rect)) {
if (!collisions.Contains(contents[i])) {
collisions.Add(contents[i]);
}
}
}
foreach(Square square in squares) {
if (square.IsVisited) {
if (item.Rect.IntersectsWith(new Rect(square.X * squareWidth, square.Y * squareHeight, squareWidth, squareHeight))) {
if (!collisions.Contains(contents[i])) {
collisions.Add(contents[i]);
}
}
}
}
}
}
}
}
从 else if
中删除 else
以确保将项目插入到其每个子节点。
if (TopLeft.Insert(item)) return true;
else if (TopRight.Insert(item)) return true;
else if (BottomLeft.Insert(item)) return true;
else if (BottomRight.Insert(item)) return true;
else return false;
应该是
var result = TopLeft.Insert(item);
result |= TopRight.Insert(item);
result |= BottomLeft.Insert(item);
result |= BottomRight.Insert(item);
return result;
另一个问题是
if (numberOfNodesInserted < max || depth == maxDepth)
如果节点被分割,你不应该向节点插入项目,所以它应该是:
if (!divided && (numberOfNodesInserted < max || depth == maxDepth))
也就是说,假设您只在叶节点中存储项目。
我有一个四叉树,但插入方法无法正常工作。现在它只插入它看到的第一个相交四边形。目的是将所有节点插入与其相交的所有四边形中。例如:当一个节点在两个四边形的边界上时,它被插入到两个四边形中。有人可以帮助我将插入方法插入到所有相交四边形中吗?
这是我当前的实现:
这是插入节点的调用:
QuadTree = new QuadTreeNode < Artist > (new Rect(0, 0, Width, Height), 1);
foreach(Artist artist in Artists) {
QuadTree.Insert(artist);
}
这是我的四叉树class:
public interface WithRect {
Rect Rect {
get;
}
}
public class QuadTreeNode < T > where T: WithRect {
Rect bounds;
List < T > contents;
int numberOfNodesInserted = 0;
int max = 4;
int depth = 0;
int maxDepth = 6;
bool divided;
QuadTreeNode < T > TopLeft;
QuadTreeNode < T > TopRight;
QuadTreeNode < T > BottomLeft;
QuadTreeNode < T > BottomRight;
public QuadTreeNode(Rect _bounds, int _depth) {
depth = _depth;
bounds = _bounds;
contents = new List < T > ();
divided = false;
}
public void DivideQuad() {
int newDepth = depth + 1;
double x = bounds.X;
double y = bounds.Y;
double width = bounds.Width;
double height = bounds.Height;
TopLeft = new QuadTreeNode < T > (new Rect(x, y, width / 2, height / 2), newDepth);
TopRight = new QuadTreeNode < T > (new Rect(x + width / 2, y, width / 2, height / 2), newDepth);
BottomLeft = new QuadTreeNode < T > (new Rect(x, y + height / 2, width / 2, height / 2), newDepth);
BottomRight = new QuadTreeNode < T > (new Rect(x + width / 2, y + height / 2, width / 2, height / 2), newDepth);
divided = true;
foreach(T item in contents) {
Insert(item);
}
contents.Clear();
}
public bool Insert(T item) {
if (!bounds.IntersectsWith(item.Rect)) return false;
if (numberOfNodesInserted < max || depth == maxDepth) {
contents.Add(item);
numberOfNodesInserted++;
return true;
}
else {
if (!divided) {
DivideQuad();
}
if (TopLeft.Insert(item)) return true;
else if (TopRight.Insert(item)) return true;
else if (BottomLeft.Insert(item)) return true;
else if (BottomRight.Insert(item)) return true;
else return false;
}
}
public void GetBounds(ref List < Rect > results) {
if (bounds != null) results.Add(bounds);
if (TopLeft != null) TopLeft.GetBounds(ref results);
if (TopRight != null) TopRight.GetBounds(ref results);
if (BottomLeft != null) BottomLeft.GetBounds(ref results);
if (BottomRight != null) BottomRight.GetBounds(ref results);
}
public void Query(T item, ref List < T > collisions, List < Square > squares, int squareWidth, int squareHeight) {
if (item.Rect.IntersectsWith(bounds)) {
if (divided) {
TopLeft.Query(item, ref collisions, squares, squareWidth, squareHeight);
TopRight.Query(item, ref collisions, squares, squareWidth, squareHeight);
BottomLeft.Query(item, ref collisions, squares, squareWidth, squareHeight);
BottomRight.Query(item, ref collisions, squares, squareWidth, squareHeight);
}
for (int i = 0; i < contents.Count; i++) {
if (item.Rect != contents[i].Rect) {
if (item.Rect.IntersectsWith(contents[i].Rect)) {
if (!collisions.Contains(contents[i])) {
collisions.Add(contents[i]);
}
}
}
foreach(Square square in squares) {
if (square.IsVisited) {
if (item.Rect.IntersectsWith(new Rect(square.X * squareWidth, square.Y * squareHeight, squareWidth, squareHeight))) {
if (!collisions.Contains(contents[i])) {
collisions.Add(contents[i]);
}
}
}
}
}
}
}
}
从 else if
中删除 else
以确保将项目插入到其每个子节点。
if (TopLeft.Insert(item)) return true;
else if (TopRight.Insert(item)) return true;
else if (BottomLeft.Insert(item)) return true;
else if (BottomRight.Insert(item)) return true;
else return false;
应该是
var result = TopLeft.Insert(item);
result |= TopRight.Insert(item);
result |= BottomLeft.Insert(item);
result |= BottomRight.Insert(item);
return result;
另一个问题是
if (numberOfNodesInserted < max || depth == maxDepth)
如果节点被分割,你不应该向节点插入项目,所以它应该是:
if (!divided && (numberOfNodesInserted < max || depth == maxDepth))
也就是说,假设您只在叶节点中存储项目。