How to stack rectangles without changing their X positions? - c++

I have set of rectangles ( QGraphicsRectItem in QGraphicsScene ) whose X positions are fixed and Y positions can be modified. I want to stack these rectangles if there is any overlapping. The positions of rectangles can be changed dynamically by moving/resizing those rectangles and each time it has to optimize the space such that there is no gaps. The important constraint is that , when we move a specific rectangle it has to stack the rectangles without modifying the X position of any other rectangle.
I have a simple brute force algorithm which traverse through all the rectangles and then gets the collidng rectangles , increment the Y position with some delta value for all colliding rectangles.
Any optimal solution for this problem?

You have to assign each rectangle to a level, so that on a given level, no two rectangles overlap. Correct? So allocate an array of levels, leaving room for the worst-case scenario of each level containing only one rectangle:
std::vector<int> LevelFreeAt (nRectangles) ;
As you traverse your list of rectangles, LevelFreeAt[i] will contain the time at which level i becomes free. Now for each rectangle, in order of starting time, simply assign it to the first level that is free at its starting time, and update that level's LevelFreeAt entry accordingly.

you could sort the rectangles by Y-Position (minimum y-position). Then you go through the list. The first one will be taken as is, the second in the list has to check if it overlaps with the previous one. If it does, adjust Y-Position to not overlap with the previous one and proceed. Do this for every rectangle in the list. After this, they do not overlap.
Restriction: it does not work if some rectangles are completely inside other rectangles (y-coordinate wise).

Related

What is the optimal algorithm for placing compatible tiles adjacent to each other?

I have a number of tiles, each with a unique ID (1,2,3....)
Each tile has information about which other tiles (there can be more than one option) are allowed to be placed directly north, south,east or west of this tile. All other tiles may not be placed in these positions.
There is no information about which tiles may or may not be placed diagonally(North East, South West etc), since that would depend on the tiles which are North,South,East or West etc of the adjacent tiles anyway.
Given a grid of size (NxM), and an initial tile in position (0,0) what is the optimal algorithm for placing tiles in a compatible manner ?
At present I have this brute force solution:
class Tile {
public:
int id;//From 0 to any number
//Each of the following vectors contain ids of which tiles may be placed immediately adjacent in that direction. If no tiles may be placed, then that vector is empty.
std::vector<int> northTiles;
std::vector<int> southTiles;
std::vector<int> eastTiles;
std::vector<int> westTiles;
}
class Layout{
public:
std::unordered_map<int,Tile> _tileIdToTile;
std::vector<std::vector<int>> tileIds; //Which tile id is placed at which coordinate
Layout(int N,int M){
}
}
Algorithm in pseudocode, to keep it concise:
Pick some tile id to start with
Start with coordinate 0,0
Place first compatible tile to the east of this tile (1,0), and keep placing compatible tiles east (2,0), (3,0) etc
If we reach the last tile in the current row, then move up a row (eg: 0,1) and continue as before, by placing tiles, that are compatible both with the tile immediately below (south), and to the west (previous tile)
If we do not have any compatible tile, then we go backwards to the last successful coordinate, and choose a different tile from remaining options. Likewise, if there is no more compatible tiles, then we go backwards to the next previous successful coordinate before this, and choose a different tile to place next.
If we are at the origin, then we choose a different starting tile
If we have placed a compatible tile at the top right coordinate, then we have a successful placement.
Since we use a vector for storing compatible tile ids, we do not need to keep track of our position, since the tile used is already stored in the layout, and we can lookup the index in the vector, to determine which tile to try next, or if we have run out of compatible tiles.
This is a simple but brute force solution, so the performance is very poor. I have glanced at other solutions which are more complex to understand.
This is a Constraint Satisfaction Problem, so you may want to apply some typical strategies/heuristics, although this will probably require to implement a full backtracking mechanism.
constraint propagation: block all assignments that are incompatible with the ones you already made
most constrained variable, also known as fail-first heuristic: try to assign a tile in the place where the maximum number of constraints apply. This will prune the search tree faster
least constraining value: once you selected which place you want to assign, try first to set the tile that leaves more open possibilities
There are lots of more complex techniques but the three above should represent a good start

"moving furniture": collision resolution in 2d space (non-rotating shrinkable 2d rectangles)

In 2d space we have a collection of rectangles.
Here's a picture:
Vertical line on the right is non-moveable "wall".
Arrow on the left shows direction of movement.
I need to move leftmost rectangle to the right.
Rectangles cannot rotate.
Rectangles are not allowed to overlap horizontally.
Rectangle can shrink (horizontally) down to a certain minimum width (which is set individually to each rectangle)
Rectangles can only move horizontally (left/right) and shrink horizontally.
Leftmost rectangle (pointed at by arrow) cannot shrink.
Widths and coordinates are stored as integers.
I need to move leftmost rectangle to the right by X units, pushing everything in its way to the right.
There are two problems:
I need to determine how far I can move leftmost rectangle to the right (it might not be possible to move for X units).
Move rect by X units (or if it is not possible to move by X units, move by maximum possible amount, smaller than X) and get new coordinates and sizes for every rectangle in the system.
Additional complications:
You cannot use Y coordinate and height of rectangle for anything, instead
every rectangle has a list (implemented as pointers) of rectangles it will hit if you keep moving it to the right, you can only retrieve x coordinate, width, and minimum width. This data model cannot be changed. (technically, reppresenting this as a set of rectangles in 2d is simplification)
Important: Children from different levels and branches can have the same rectangle in the "potential collision" list. Here's initial picture with pointers displayed as red lines:
How can I do it?
I know a dumb way (that'll work) to solve this problem: iteratively. I.e.
Memorize current state of the system. If state of the system is already memorized, forget previously memorized state.
Push leftmost rect by 1 unit.
Recursively resolve collisions (if any).
If collision could not be resolved, return memorized state of the system.
If collisions could be resolved, and we already moved by X units, return current state of the system.
Otherwise, go to 1.
This WILL solve the problem, but such iterative solution can be slow if X is large. Is there any better way to solve it?
One possible solution that comes to mind:
You said that each rectangle holds pointers to all the objects it will hit when moving right. I would suggest, take the list of pointers from the big rectangle (the one pointed by the arrow), take all it's nodes (the rectangles it would collide), find the min width, then do the same of all the child nodes, add the widths for each branch recursively. Treat the problem like a tree depth problem. Every node has a min width value so the answer to your question would be the distance between the wall and the x value of the right edge of the big rectangle minus the GREATEST sum of the least width of the rectangles. Create a vector where the depth (sum of min widths) of each branch of the tree is stored and find the max value. Distance minus max is your answer.
imagine the same picture with 4 boxes. one to the left, one to the right and then the wall. lets name them box 1, box 2 (mid top), box 3 (mid bottom) and the last one box 4 (right). each box has a width of 4. all can shrink except the left one. box 2 can shrink by 2, box 3 can shrink by 1, box 4 can shrink by 2. Calculating the 2 branches gives
* Branch 1 : 2 + 2 = 4
* Branch 2 : 3 + 2 = 5
* Only concerned with branch 2 because branch 1 is LESS than branch 2 hence will fit in the space parallel to branch 2and is available to shrink that much.

Given a rectangular area and a set of rectangles, check if the entire area is covered by them [duplicate]

This question already has answers here:
Rectangles Covering
(12 answers)
Closed 5 years ago.
All values here are real numbers with up to two floating point digits.
Suppose we have a rectangular area, 100.0 by 75.0.
Then you are given a set of rectangles. How can I check whether these rectangles, united, cover the entire area?
If we have
(0,0,50,75)
clearly this does not happen since it only covers half the area. If we have
(0,0,50,75)
(50,0,50,75)
Then this does work, since both rectangles will effectively cover the whole (100,75).
What have I tried
I attempted (didn't work) to make a multi-dimensional array of booleans:
bool area[10000][7500];
These are the dimensions of the area, multiplied by 100 so that I don't have to deal with the floating points. Then I just iterate each of my rectangles (their values also multiplied by 100), and for each "pixel" in them, I turn the boolean to true.
Ultimately, I check if all booleans in the area are true.
This proved to be very dumb. Can you help me find a better way to do this?
I think a strategy like this will work:
Throw away any rectangles that are completely outside your area
Split your area in smaller rectangles along the edges of the rectangles in the list relative to one axis
Split the list of area rectangles created in step 2 along the edges of the rectangles in the cover list relative to the other axis
You now have two lists of rectangles where there must be one in the cover list that covers each of the area rectangles completely
I believe your "bitmap" attempt failed because of the (usual) floating point rounding problems. Unfortunately there's little you can do about it.
Now for the algorithm proper, I would approach it using a subtraction technique.
Let's call your initial set of rectangles R.
Initialize a second set of rectangles S that initially contains a single rectangle covering the whole area.
For each rectangle in R:
For each rectangle in S:
If the two R and S rectangles intersect, replace the S rectangle with as many rectangles as needed (0 to 4 if I'm not mistaken) that cover the non-intersecting part left from the S rectangle.
Continue iterating over S, taking care not to compute anything for the new S rectangles you just added (which we already know don't intersect with the current R rectangle).
Continue iterating over R, this time taking the new S rectangles into account, until either:
There is no rectangle left in S, in which case your R rectangles do cover the whole area.
Or, you iterated over all R rectangles and there are still S rectangles left, in which case your R rectangles don't cover the whole area.
As for the complexity, I'm not sure how it compares to #500-Internal-Server-Error or #Tommy's solutions but hey, at least I managed to come up with something, which I didn't think I could when I read your question at first -- I'm usually not very good at spatial stuff. :)
A conceptually very similar approach to 500 - Internal Server Error's that avoids the O(n^2) search implied by the final step is:
build a list of the vertical boundaries of every rectangle from the covering set;
supposing that makes n boundaries, you've got n+1 vertical strips to consider on the source rectangle;
for each strip, get the list of all rectangles that overlap it (you can do this in O(n) time by pushing from the rectangles to the bins rather than searching backwards);
sort the lists from left to right (ie, O(n log n));
go through the sorted list and try to find a gap where one span ends and nothing else begins until a little later (another O(n) task).
If you find a suitable gap then the original isn't covered. If you don't then it is. And this is essentially how span buffering works, by the way.

find overlapping rectangles algorithm

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 coordinates whose coordinates are moving (but you can assume that its size is constant)
What is the most efficient way to find which rectangles are intersecting (or inside) A?
I cannot simply loop through my set as it is too big. Thanks
edit : the rectangles are all parallel to the axis
I'll bet you could use some kind of derivation of a quadtree to do this. Take a look at this example.
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.
You can create two vectors of rectangle indexes (because two diagonal points uniquely define your rectangle), and sort them by one of coordinates. Then you search for overlaps using those two index arrays, which is going to be logarithmic instead of linear complexity.
You can do a random "walking" algorithm ... basically create a list of neighbors for all your fixed position rectangles. Then randomly pick one of the fixed-position rectangles, and check to see where the target rectangle is in comparison to the current fixed-position rectangle. If it's not inside the rectangle you randomly picked as the starting point, then it will be in one of the eight directions which correspond to a given neighbor of your current fixed position rectangle (i.e., for any given rectangle there will be a rectangle in the N, NE, E, SE, S, SW, W, NW directions). Pick the neighboring rectangle in the closest given direction to your target rectangle, and re-test. This is essentially a randomized incremental construction algorithm, and it's performance tends to be very good for geometric problems (typically logarithmic for an individual iteration, and O(n log n) for repeated iterations).
Create a matrix containing "quadrant" elements, where each quadrant represents an N*M space within your system, with N and M being the width and height of the widest and tallest rectangles, respectively. Each rectangle will be placed in a quadrant element based on its upper left corner (thus, every rectangle will be in exactly one quadrant). Given a rectangle A, check for collisions between rectangles in the A's own quadrant and the 8 adjacent quadrants.
This is an algorithm I recall seeing recommended as a simple optimization to brute force hit-tests in collision detection for game design. It works best when you're mostly dealing with small objects, though if you have a couple large objects you can avoid wrecking its efficiency by performing collision detection on them separately and not placing them in a quadrant, thus reducing quadrant size.
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.
Topcoder provides a way to determine if a point lies within a rectangle. It says that say we have a point x1,y1 and a rectangle. We should choose a random point very far away from current locality of reference in the rectangular co-ordinate system say x2,y2.
Now we should make a line segment with the points x1,y1 and x2,y2. If this line segment intersects odd number of sides of the given rectangle (it'll be 1 in our case, this method can be extended to general polygons as well) then the point x1,y1 lies inside the rectangle and if it intersects even number of sides it lies outside the rectangle.
Given two rectangles, we need to repeat this process for every vertex of 1 triangle to possibly lie in the second triangle. This way we'd be able to determine if two rectangles overlap even if they are not aligned to the x or y axis.
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
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.
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
Method (A)
You could use an interval tree or segment tree. If the trees were created so that they would be balanced this would give you a run time of O(log n). I assume this type of preprocessing is practical because it would only happen once (it seems like you are more concerned with the runtime once the rectangle starts moving than you are with the amount of initial preprocessing for the first time). The amount of space would be O(n) or O(n log n) depending on your choice above.
Method (B)
Given that your large set of rectangles are of fixed size and never change their coordinates and that they are non-overlapping, you could try a somewhat different style of algorithm/heuristic than proposed by others here (assuming you can live with a one-time, upfront preprocessing fee).
Preprocessing Algorithm [O(n log n) or O(n^2) runtime {only run once though}, O(n) space]
Sort the rectangles by their horizontal coordinates using your favorite sorting algorithm (I am assuming O(n log n) run time).
Sort the rectangles by their vertical coordinates using your favorite sorting algorithm (I am assuming O(n log n) run time)
Compute a probability distribution function and a cumulative distribution function of the horizontal coordinates. (Runtime of O(1) to O(n^2) depending on method used and what kind of distribution your data has)
a) If your rectangles' horizontal coordinates follow some naturally occurring process then you can probably estimate their distribution function by using a known distribution (ex: normal, exponential, uniform, etc.).
b) If your rectangles' horizontal coordinates do not follow a known distribution, then you can calculate a custom/estimated distribution by creating a histogram.
Compute a probability distribution function and a cumulative distribution function of the vertical coordinates.
a) If your rectangles' vertical coordinates follow some naturally occurring process then you can probably estimate their distribution function by using a known distribution (ex: normal, exponential, uniform, etc.).
b) If your rectangles' vertical coordinates do not follow a known distribution, then you can calculate a custom/estimated distribution by creating a histogram.
Real-time Intersection Finding Algorithm [Anywhere from O(1) to O(log n) to O(n) {note: if O(n), then the constant in front of n would be very small} run time depending on how well the distribution functions fit the dataset]
Taking the horizontal coordinate of your moving rectangle and plug it into the cumulative density function for the horizontal coordinates of the many rectangles. This will output a probability (value between 0 and 1). Multiply this value times n (where n is the number of many rectangles you have). This value will be the array index to check in the sorted rectangle list. If the rectangle of this array index happens to be intersecting then you are done and can proceed to the next step. Otherwise, you have to scan the surrounding neighbors to determine if the neighbors intersect with the moving rectangle. You can attack this portion of the problem multiple ways:
a) do a linear scan until finding the intersecting rectangle or finding a rectangle on the other side of the moving rectangle
b) calculate a confidence interval using the probability density functions you calculated to give you a best guess at potential boundaries (i.e. an interval where an intersection must lie). Then do a binary search on this small interval. If the binary search fails then revert back to a linear search in part (a).
Do the same thing as step 1, but do it for the vertical portions rather than the horizontal parts.
If step 1 yielded an intersection and step 2 yielded an intersection and the intersecting rectangle in step 1 was the same rectangle as in step 2, then the rectangle must intersect with the moving rectangle. Otherwise there is no intersection.
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

Finding largest rectangle in 2D array

I need an algorithm which can parse a 2D array and return the largest continuous rectangle. For reference, look at the image I made demonstrating my question.
Generally you solve these sorts of problems using what are called scan line algorithms. They examine the data one row (or scan line) at a time building up the answer you are looking for, in your case candidate rectangles.
Here's a rough outline of how it would work.
Number all the rows in your image from 0..6, I'll work from the bottom up.
Examining row 0 you have the beginnings of two rectangles (I am assuming you are only interested in the black square). I'll refer to rectangles using (x, y, width, height). The two active rectangles are (1,0,2,1) and (4,0,6,1). You add these to a list of active rectangles. This list is sorted by increasing x coordinate.
You are now done with scan line 0, so you increment your scan line.
Examining row 1 you work along the row seeing if you have any of the following:
new active rectangles
space for existing rectangles to grow
obstacles which split existing rectangles
obstacles which require you to remove a rectangle from the active list
As you work along the row you will see that you have a new active rect (0,1,8,1), we can grow one of existing active ones to (1,0,2,2) and we need to remove the active (4,0,6,1) replacing it with two narrower ones. We need to remember this one. It is the largest we have seen to far. It is replaced with two new active ones: (4,0,4,2) and (9,0,1,2)
So at the send of scan line 1 we have:
Active List: (0,1,8,1), (1,0,2,2), (4,0,4,2), (9, 0, 1, 2)
Biggest so far: (4,0,6,1)
You continue in this manner until you run out of scan lines.
The tricky part is coding up the routine that runs along the scan line updating the active list. If you do it correctly you will consider each pixel only once.
Hope this helps. It is a little tricky to describe.
I like a region growing approach for this.
For each open point in ARRAY
grow EAST as far as possible
grow WEST as far as possible
grow NORTH as far as possible by adding rows
grow SOUTH as far as possible by adding rows
save the resulting area for the seed pixel used
After looping through each point in ARRAY, pick the seed pixel with the largest area result
...would be a thorough, but maybe not-the-most-efficient way to go about it.
I suppose you need to answer the philosophical question "Is a line of points a skinny rectangle?" If a line == a thin rectangle, you could optimize further by:
Create a second array of integers called LINES that has the same dimensions as ARRAY
Loop through each point in ARRAY
Determine the longest valid line to the EAST that begins at each point and save its length in the corresponding cell of LINES.
After doing this for each point in ARRAY, loop through LINES
For each point in LINES, determine how many neighbors SOUTH have the same length value or less.
Accept a SOUTHERN neighbor with a smaller length if doing so will increase the area of the rectangle.
The largest rectangle using that seed point is (Number_of_acceptable_southern_neighbors*the_length_of_longest_accepted_line)
As the largest rectangular area for each seed is calculated, check to see if you have a new max value and save the result if you do.
And... you could do this without allocating an array LINES, but I thought using it in my explanation made the description simpler.
And... I think you need to do this same sort of thing with VERTICAL_LINES and EASTERN_NEIGHBORS, or some cases might miss big rectangles that are tall and skinny. So maybe this second algorithm isn't so optimized after all.
Use the first method to check your work. I think Knuth said "...premature optimization is the root of all evil."
HTH,
Perry
ADDENDUM:Several edits later, I think this answer deserves a group upvote.
A straight forward approach would be to do a loop through all the potential rectangles in the grid, figure out their area, and if it is greater than the current highest area, select it as the highest:
var biggestFound
for each potential rectangle:
if area(this potential rectangle) > area(biggestFound)
biggestFound = this potential rectangle
Then you simply need to find the potential rectangles.
for each square in grid:
recursive loop 1:
if not occupied:
grow right until occupied, and return a rectangle
grow down one and recurse (call loop 1)
This will duplicate a lot of work (for example you will re-evaluate a lot of sub-rectangles), but it should give you an answer.
Edit
An alternate approach might be to start with a single square the size of the grid, and "subtract" occupied squares to end up with a final set of potential rectangles. There might be optimization opportunities here using quadtrees, and in ensuring that you keep split rectangles "in order", top to bottom, left to right, in case you need to re-combine rectangles farther down in the algorithm.
If you are actually starting out with rectangular data (for your "populated grid" set), instead of a loose pixel grid, then you could easily get better perf out of a rectangle/region subtracting algorithm.
I'm not going to post pseudo-code for this because the idea is completely experimental, and I have no idea if the perf will be any better for a loose pixel grid ;)
Windows system "regions" and "dirty rectangles", as well as general "temporal caching" might be good inspiration here for more efficiency. There are also a lot of z-buffer tricks if this is for a graphics algorithm...
Use dynamic programming approach. Consider a function S(x,y) such that S(x,y) holds the area of the largest rectangle where (x,y) are the lowest-right-most corner cell of the rectangle; x is the row co-ordinate and y is the column co-ordinate of the rectangle.
For example, in your figure, S(1,1) = 1, S(1,2)=2, S(2,1)=2, and S(2,2) = 4. But, S(3,1)=0, because this cell is filled. S(8,5)=40, which says that the largest rectangle for which the lowest-right cell is (8,5) has the area 40, which happens to be the optimum solution in this example.
You can easily write a dynamic programming equation of S(x,y) from the value of S(x-1,y), S(x,y-1) and S(x-1,y-1). Using that you can obtain the values of all S(x,y) in O(mn) time, where m and n are the row and column dimension of the given table. Once, S(x,y) are know for all 1<=x <= m, and for all 1 <= y <= n, we simply need to find the x, and y for which S(x,y) is the largest; this step also takes O(mn) time. By keeping addition data, you can also find the side-length of the largest rectangle.
The overall complexity is O(mn). To understand more on this, Read Chapter 15 or Cormen's algorithm book, specifically Section 15.4.