最小边界四叉树节点
我正在编写一个基于整数的四叉树结构,它从节点开始构建,而不是向下构建。为此,我需要发现包含所有元素的下一个最大节点。如果我定义了一个预先存在的节点,然后尝试在该节点的边界之外添加一个项目,则需要创建一个更大的节点来包含它们。我有(我认为很聪明)用于查找单个点周围的边界框的代码:
public static Rectangle BoundingRectangle(Point p, int magnitude)
{
Rectangle bounds = new Rectangle()
{
X = (p.X & ~((1 << magnitude) - 1)),
Y = (p.Y & ~((1 << magnitude) - 1)),
Width = (1 << magnitude),
Height = (1 << magnitude)
};
return bounds;
}
[请注意,点 (0,0) 周围的框是位置处大小为 (1,1) 的框(0,0),不在位置(-.5,-.5),因为它都是基于整数的]
这将始终(据我所知)返回一个适合的框成四叉树作为节点。例如,new Rectangle(0,0,2,2)
是可以接受的,new Rectangle(2,2,2,2)
也是可以接受的,但是 new Rectangle(1,1,2,2)
则不会。
我的问题是我不知道如何为矩形而不是点来完成此操作。我能想到的唯一解决方案是循环遍历大小不断增加的框,但我确信必须有一些我无法想到的 O(1) 解决方案。
示例:
Rectangle(X,Y,1,1) -> Rectangle(X,Y,1,1)
Rectangle(0,0,2,2) -> Rectangle(0,0,2,2)
Rectangle(1,1,2,2) -> Rectangle(0,0,4,4)
Rectangle(1,1,3,3) -> Rectangle(0,0,4,4)
Rectangle(0,5,2,2) -> Rectangle(0,4,4,4)
Rectangle(3,3,2,2) -> Rectangle(0,0,8,8)
实现:
private static int BitScanReverse(int mask)
{
int index = 0;
while (mask > 1)
{
mask >>= 1;
index++;
}
return index;
}
public static Rectangle BoundingRectangle(Point p, int magnitude)
{
Rectangle bounds = new Rectangle()
{
X = (p.X & ~((1 << magnitude) - 1)),
Y = (p.Y & ~((1 << magnitude) - 1)),
Width = (1 << magnitude),
Height = (1 << magnitude)
};
return bounds;
}
public static Rectangle BoundingRectangle(Rectangle r, int magnitude)
{
int msb = BitScanReverse((r.X ^ (r.X + r.Width - 1)) | (r.Y ^ (r.Y + r.Height - 1)));
return BoundingRectangle(r.Location, Math.Max(msb + 1, magnitude));
}
I'm writing an integer-based quadtree structure which builds up from the node, and not down. To do this, I need to discover the next largest node which contains all my elements. If I have a preexisting node defined, then try to add an item outside of that node's bounds, it needs to create a larger node to encompass them both. I have (what I think is clever) code for finding the bounding box around a single point:
public static Rectangle BoundingRectangle(Point p, int magnitude)
{
Rectangle bounds = new Rectangle()
{
X = (p.X & ~((1 << magnitude) - 1)),
Y = (p.Y & ~((1 << magnitude) - 1)),
Width = (1 << magnitude),
Height = (1 << magnitude)
};
return bounds;
}
[Note that the box around point (0,0) is a boxof size (1,1) at location (0,0), not at location (-.5,-.5), since it's all integer-based]
This will always (from what I can tell,) return a box which would fit into a quadtree as a node. For example, new Rectangle(0,0,2,2)
would be acceptable, as would new Rectangle(2,2,2,2)
, but new Rectangle(1,1,2,2)
would not be.
My problem is that I can't figure out how to accomplish this for a rectangle, instead of a point. The only solution I can think of would be to loop through boxes of increasing magnitude, but I'm sure there has to be some O(1) solution I'm just not able to think of.
Examples:
Rectangle(X,Y,1,1) -> Rectangle(X,Y,1,1)
Rectangle(0,0,2,2) -> Rectangle(0,0,2,2)
Rectangle(1,1,2,2) -> Rectangle(0,0,4,4)
Rectangle(1,1,3,3) -> Rectangle(0,0,4,4)
Rectangle(0,5,2,2) -> Rectangle(0,4,4,4)
Rectangle(3,3,2,2) -> Rectangle(0,0,8,8)
Implementation:
private static int BitScanReverse(int mask)
{
int index = 0;
while (mask > 1)
{
mask >>= 1;
index++;
}
return index;
}
public static Rectangle BoundingRectangle(Point p, int magnitude)
{
Rectangle bounds = new Rectangle()
{
X = (p.X & ~((1 << magnitude) - 1)),
Y = (p.Y & ~((1 << magnitude) - 1)),
Width = (1 << magnitude),
Height = (1 << magnitude)
};
return bounds;
}
public static Rectangle BoundingRectangle(Rectangle r, int magnitude)
{
int msb = BitScanReverse((r.X ^ (r.X + r.Width - 1)) | (r.Y ^ (r.Y + r.Height - 1)));
return BoundingRectangle(r.Location, Math.Max(msb + 1, magnitude));
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
让我们首先考虑它的一维版本。我们没有矩形,而是有偏移量和长度。
边界矩形的“大小”告诉您要忽略多少位。
假设 offset = 1234 且 length = 56。我们希望忽略足够多的位,以便“offset”(1234) 和“offset+length-1”(1289) 映射到相同的数字。
显然,我们需要在这里忽略除前 2 位之外的所有位(忽略 9 位)。
我们可以通过编程方式使用 1234 XOR 1289(即 475)找到这一点,
然后找到 475 的最高有效设置位。大多数处理器都有这条指令(在 Windows 上,它是 _BitScanReverse)。
现在,对于 2D 情况,我们需要对 X 轴和 Y 轴进行异或。然后,我们将这两个结果进行“或”运算。最后,找到最高有效的设置位。
因此,在伪代码中:
要获取实际的矩形,只需使用帖子中的函数即可。传入新的Point(X,Y)。
Let's consider the one-dimensional version of this first. Instead of a rectangle, we have an offset and length.
The 'magnitude' of your bounding rectangle is telling you how many bits to ignore.
Let's say offset = 1234 and length = 56. We want to ignore enough bits so that 'offset' (1234) and 'offset+length-1' (1289) map to the same number.
Clearly, we need to ignore all but the first 2 bits here (ignore 9 bits).
We can find this programmatically with 1234 XOR 1289 (which is 475)
and then finding the most significant set bit of 475. Most processors have this instruction (on Windows, it's _BitScanReverse).
Now, for your 2D case, we need to get the XOR for both the X-axis and Y-axis. Then, we OR those two results together. Finally, find the most significant set bit.
So, in pseudo-code:
To get the actual rectangle, just use the function in your post. Pass in new Point(X, Y).