let\'s say I have a huge set of non-overlapping rectangle with integer coordinates, who are fixed once and for all
I have another rectangle A with integer coordinate
By calculating the area of each rectangle and and checking the length L, height H and area of rectangles whether exceeds or not the length and height and area of a rectangle A
Use an R+ tree, which is most likely precisely the specific tree structure you are looking for. R+ trees explicitly do not allow overlapping in the internal (non-leaf) structure in exchange for speed. As long as no object exists in multiple leaves at once, there is no overlap. In your implementation, rather than support overlap, whenever an object needs to be added to multiple leaves, just return true instead.
Here is a detailed description of the data structure, including how to manage rectangles: The R+-tree: A dynamic index for multi-dimensional objects
Interval Trees: Are BSTs designed with taking 'lo' value as key in an interval. So, for example if we want to insert (23, 46) in the tree, we'd insert it using '23' in the BST.
Also, with interval trees at each node, we keep the maximum endpoint (hi value) of the sub-tree rooted at that node.
This order of insertion allows us to search all 'R' intersections in R(logN) time. [We search for first intersection in logN time and all R in RlogN time] Please refer to interval trees documentation for how insert, search is done and details of complexity.
Now for this problem, we use an algorithm known as sweep-line algorithm. Imagine we have a vertical line (parallel to y-axis) which is sweeping the 2D space and in this process intersects with the rectangles.
1) Arrange rectangles in increasing order of x-cordinates (left-edge wise) either via priority queue or via sorting . Complexity NlogN if N rectangles.
2) As this line sweeps from left to right, following are the intersection cases:
If line intersects the left side of a rectangle never seen, add the y co-ords of the rectangle's side to the interval tree. [say (x1,y1) and (x1,y2) are left edge co-ordinates of the rectangle add interval (y1, y2) to the interval tree] ---> (NlogN)
Do a range search on the interval tree. [say (x1,y1) and (x1,y2) are left edge co-ordinates of the rectangle, take the interval (y1,y2) and do an interval intersection query on the tree to find all intersections] ---> RlogN (in practice)
If line intersects the right side of a rectangle, remove it's y-coords from the interval tree as the rectangle is now processed completely. ----> NlogN
Total complexity : NlogN + RlogN
Personally, I would solve this with a KD-Tree or a BIH-Tree. They are both adaptive spatial data structures that have a log(n) search time. I have an implementation of both for my Ray Tracer, and they scream.
-- UPDATE --
Store all of your fixed rectangles in the KD-Tree. When you are testing intersections, iterate through the KD-Tree as follows:
function FindRects(KDNode node, Rect searchRect, List<Rect> intersectionRects)
// searchRect is the rectangle you want to test intersections with
// node is the current node. This is a recursive function, so the first call
// is the root node
// intersectionRects contains the list of rectangles intersected
int axis = node.Axis;
// Only child nodes actually have rects in them
if (node is child)
{
// Test for intersections with each rectangle the node owns
for each (Rect nRect in node.Rects)
{
if (nRect.Intersects(searchRect))
intersectionRects.Add(nRect);
}
}
else
{
// If the searchRect's boundary extends into the left bi-section of the node
// we need to search the left sub-tree for intersections
if (searchRect[axis].Min // Min would be the Rect.Left if axis == 0,
// Rect.Top if axis == 1
< node.Plane) // The absolute coordinate of the split plane
{
FindRects(node.LeftChild, searchRect, intersectionRects);
}
// If the searchRect's boundary extends into the right bi-section of the node
// we need to search the right sub-tree for intersections
if (searchRect[axis].Max // Max would be the Rect.Right if axis == 0
// Rect.Bottom if axis == 1
> node.Plane) // The absolute coordinate of the split plane
{
FindRects(node.RightChild, searchRect, intersectionRects);
}
}
This function should work once converted from pseudo-code, but the algorithm is correct. This is a log(n) search algorithm, and possibly the slowest implementation of it (convert from recursive to stack based).
-- UPDATE -- Added a simple KD-Tree building algorithm
The simplest form of a KD tree that contains area/volume shapes is the following:
Rect bounds = ...; // Calculate the bounding area of all shapes you want to
// store in the tree
int plane = 0; // Start by splitting on the x axis
BuildTree(_root, plane, bounds, insertRects);
function BuildTree(KDNode node, int plane, Rect nodeBds, List<Rect> insertRects)
if (insertRects.size() < THRESHOLD /* Stop splitting when there are less than some
number of rects. Experiment with this, but 3
is usually a decent number */)
{
AddRectsToNode(node, insertRects);
node.IsLeaf = true;
return;
}
float splitPos = nodeBds[plane].Min + (nodeBds[plane].Max - nodeBds[plane].Min) / 2;
// Once you have a split plane calculated, you want to split the insertRects list
// into a list of rectangles that have area left of the split plane, and a list of
// rects that have area to the right of the split plane.
// If a rect overlaps the split plane, add it to both lists
List<Rect> leftRects, rightRects;
FillLists(insertRects, splitPos, plane, leftRects, rightRects);
Rect leftBds, rightBds; // Split the nodeBds rect into 2 rects along the split plane
KDNode leftChild, rightChild; // Initialize these
// Build out the left sub-tree
BuildTree(leftChild, (plane + 1) % NUM_DIMS, // 2 for a 2d tree
leftBds, leftRects);
// Build out the right sub-tree
BuildTree(rightChild, (plane + 1) % NUM_DIMS,
rightBds, rightRects);
node.LeftChild = leftChild;
node.RightChild = rightChild;
There a bunch of obvious optimizations here, but build time is usually not as important as search time. That being said, a well build tree is what makes searching fast. Look up SAH-KD-Tree if you want to learn how to build a fast kd-tree.
Let your set of rectangle be (Xi1,Yi1,Xi2,Yi2) where i varies from 0 to N.
Rectangle A and B can NOT be intersecting if Ax1 > Bx2 || Ay1 < By2 || Bx1 > Ax2 || By1 < Ay2.
Create tree which is optimized for range/interval (For exa: segment tree or interval tree) See http://w3.jouy.inra.fr/unites/miaj/public/vigneron/cs4235/l5cs4235.pdf
Use this tree to find set of triangle while your triangle is changing coordinates.
As they are not overlapping I would suggest an approach similar (but not equal) to Jason Moore (B). Sort your array by x of upper left corner. And sort a copy by y of upper left corner. (of course you would just sort pointers to them to save memory).
Now you once create two sets Sliding_Window_X and Sliding_Window_Y.
You search with binary search once your x-coordinate (upper left) for your A window in the x-sorted array and your y-coordinate. You put your results into the corrospondng Sliding_Window_Set. Now you add all following rectangles in the ordered array that have a lower x(y) (this time lower right) coordinate than your lower right of A.
The result is that you have in your Sliding_Window-sets the windows that overlap with your A in one coordinate. The overlapping of A is the intersection of Sliding_Window_X and _Y.
The Sliding_Window sets can be easily represented by just 2 numbers (begin and end index of the corrosponding sorted array).
As you say you move A, it is now really easy to recalculate the overlap. Depending on the direction you can now add/remove Elements to the Sliding_Window set. I.e. you take just the next element from the sorted array at the front/end of the set and maybe remove on at the end.