How to get minimum-sized rectangle that contains certain rectangles? - algorithm

Recently I am thinking of an algorithm that can calculate the minimum-sized rectangle that contains certain rectangles.
The goal of this algorithm is to generate a big rectangle that I can put all given smaller rectangles in. One of these smaller rectangles should not partly or entirely overlap another. And before I put smaller rectangles in the big rectangle, I can rotate them 90 degrees or not. The big rectangle should be as small as it can be.
Does anyone have some clues about it?

I was researching on this issue for some time. And I've come up with a solution reference to some links and articles about this issue. Here are two of the names of articles:,. You can google and download them if you want to read these articles.
It's a pity that none of the articles can exactly solve my problem. Because what I want is neither to check if certain rectangles can be put into a fix-sized large rectangle nor a best area-allocating method that cost long time to result. So I have to balance between time and effect. I do this:
1.I prepare a list of candidate points and add the left-top point to it.
2.I place rectangles one by one into the large rectangle.
3.Every time when I place a rectangle, I check all candidate points to see if I can put the rectangle on the point. And I just keep the best two or three ones(best means minimum-sized if this rectangle is the last one).
4.I choose a candidate point to place the rectangle and replace one point to two points(right-top point and left-bottom one of the rectangle) if they are checked valid to place the next rectangle.
5.I recursively do step 3 to place a next rectangle.
I use C++ language do coding so I can code like this:
void computeMinimunRects(int index, Array objects, Array candidates, RectChecker checker)
{
if (index == objects.count()){
checkresult(objects);// finished putting all rectangles
return;
}
int c = 2;// or 3 which based on objects.count()
SortPoint possibles;// SortPoint sort all input points by total area from small to big.
for (int i = 0; i<candidates.count(); i++){
if (checkput(candidates[i], objects[index].size))// check if objects[index].size can put on candidates[i] point
possibles.insert(candidates[i], objects[index].size);// input all needed value and sort them.
}
for(int i = 0; i<c; i++){
Point pt = possibles[i].pt;
Size size = possibles[i].size;
Rect rect(pt, size);
candidate.remove(pt);// replace point with two ones.
candidate.add(rect.right_top());
candidate.add(rect.left_bottom());
computeMinimunRects(index+1, objects, candidates, checker);// recursively input rectangle
candidates.remove(rect.right_top());// revert all changes
candidates.remove(rect.left_bottom());
candidates.add(pt);
}
}

Related

Split Up Big Polygon Into Smaller Ones By Condition

I have some big Polygon. Within it collection of leaflet layers (points). Every point have some numeric property. What I want is split up big Polygon into smaller ones.
Every smaller polygon should contain points with ~equal (+-200 ok) sum of points properties. On the left side of my example page I added image of desirable result.
Here is my simplified example with sufficient code and comments.
So my first step is find some start point within big Polygon. It's should be point near Polygon edge - the northernmost point for example.
var nothernmostPoint= 0;
var nothernmostLayer= 0;
L.geoJSON(features, {
pointToLayer: function (feature) {
return L.circleMarker(feature.geometry.coordinates.reverse(), defaultPointStyle);
},
onEachFeature: function (feature, layer) {
if (feature.geometry.coordinates[0] > nothernmostPoint) {
nothernmostPoint = feature.geometry.coordinates[0];
nothernmostLayer = feature;
}
}
}).addTo(map);
Second step is to find next nearest point(s) to my start point.
var geoJ = L.GeometryUtil.nClosestLayers(map, features, nothernmostLayer.geometry.coordinates, 5);
Then sum up their properties. If sum is smaller than needed I go to step 2 and repeat, if sum is satisfy condition then I draw polygon with chosen points inside it and find nearest point to my last point and repeat search for points for the next smaller polygon.
My current difficulty is to find nearest point(s) to my start point. For that purpose I use GeometryUtil Leaflet plugin. Red dots are points that GeometryUtil found as nearest to my start point (the green one). It's certainly not what I was expected. What am I doing wrong? Maybe I should use different algorithm and/or tool for that task? Any useful suggestions greatly appreciated.
If it may help - all that data I store in PostgreSQL with PostGIS extension. Maybe this can be done on database level.
If your dataset is rather small, you can go brute force way in PostGIS:
for each point, generate N points that represent the 'weight', using select geom, generate_series(0, weight);
decide on number of clusters you want to get, approximately sum(weight)/desired_sum;
run K-Means clustering on dataset, https://postgis.net/docs/manual-2.3/ST_ClusterKMeans.html
draw a polygon around each cluster using ST_ConvexHull(ST_Collect(geom)).

what algorithm or approach for placing rectangles without overlapp

I have a big rectangle of size 12*12. Now I have 6 rectangles already placed on the floor of that rectangle. I know the center coordinate of that pre-placed module. Now I have few another 14 rectangles to place upon that floor of that rectangle. How to do so?
here all my pre placed block those having center coordinate as say (2,5),(5,7),(9,2),(7,8),(11,9),(3,11).
Now how could I place 14 another rectangle in this floor so that it would not over lap with any preplaced block.
I would like to code in MATLAB..but what approach should I follow?
If a nice even placement is important, I suggest you look up simulated force-based graph layout. In this problem, you'll use simulated forces pushing the rectangles apart and also away from the border rectangle according to Coulomb's law. The initial configuration is randomly selected. You'll want to give the rectangles mass proportional to their area, I think. You don't have any spring forces due to edges, which makes it easier. The iteration to solve the differential equations of motion will be easy in Matlab. Or there may well be a toolkit to do it for you. Animations of these algorithms are fun.
Unfortunately with constrained problems like this, the fixed rectangles can form barriers that prevent the moving rectangles from getting to a non-overlapping solution. (Think of the case where the fixed rectangles are in a line down the middle and all the moving ones get "trapped" on one side or the other. The same thing happens in graph layout if some nodes have fixed locations.) There are various strategies for overcoming these bad cases. One is to start with no fixed objects at all, let the moving rectangles come to an equilibrium, then add the fixed ones one at a time, largest first, allowing the system regain equilibrium each time. Another, simpler one is just to start from different random initial conditions until you find one that works. There are also approaches related to simulated annealing, which is too big a topic to discuss here.
Here is a function to check overlap for two rectangles. you could loop it to check for more number of rectangles based on #Dov's idea.
For two rectangles Ri, i = 1,2, with centers (xi,yi) and half-lengths of their sides ai,bi > 0 (assuming that the sides are aligned with the coordinate axes).
Here is my implementation based on above equation:
In my code i've taken xcPosition and ycPosition as the center position of the rectangle.
Also length and breadth are the magnitude of sides of the rectangle.
function [ overLap, pivalue ] = checkOverlap( xcPosition1,ycPosition1,xcPosition2,ycPosition2,length1,breadth1,length2,breadth2 )
pix = max((xcPosition2 - xcPosition1 -(length1/2)-(length2/2)),(xcPosition1 -xcPosition2 -(length2/2)-(length1/2)));
piy = max((ycPosition2 - ycPosition1 -(breadth1/2)-(breadth2/2)),(ycPosition1 -ycPosition2 -(breadth2/2)-(breadth1/2)));
pivalue = max(pix, piy);
if (pivalue < 0)
overLap = 1; %// Overlap exists
else
overLap = 0; %// No overlap
end
end
You could also use the pivalue to know the degree of overlap or Non-overlap
The Pseudo-code for looping would be something like this:
for i = 1 : 14
for j = 1 : i-1 + 6 already placed parts
%// check for overlap using the above function here
%// place the part if there is no overlap
end
end
With such a small number, put each rectangle in a list. Each time you add a new rectangle, make sure the new one does not overlap with any of the existing ones.
This is O(n^2), so if you plan to increase to 10^3 or more rectangles you will need a better algorithm, but otherwise you're fine.
Now if your problem specifies that you might not be able to fit them all, then you will have to backtrack and keep trying different places. That is an N! problem, but if you have a lot of open space, many solutions will be possible.

Efficiently filling empty cells in 3D matrix

I have a 3D "cubical" matrix, with some cells filled and others empty. A closed region enclosed by filled cells represents a hollow shape. For example, the matrix could have cells filled in such a way that together they form the surface of a hollow sphere. Now, I want an efficient way to fill the interior of this sphere: if a cell C0 is surrounded in all directions by filled cells (filled cell in any direction need not be an immediate neighbor of C0), then fill C0.
A naive way would be the following :-
For each cell, scan in the +X, -X, +Y, -Y, +Z, -Z direction, and see
if you encounter a filled cell in each and every direction.
If a filled cell is encountered in each and every direction, then fill this
cell (as it is part of the interior of some shape).
If you reach the end of grid even in one direction without encountering any filled
cell, then the cell under consideration is not interior to any shape,
and should remain unfilled.
The complexity of above approach is O(n^4), where dimension of 3D grid is n*n*n.
An optimization could be to as follows :-
If for an unfilled cell C[x][y][z], we encountered one filled cell
each in all the 6 directions, then not only C[x][y][z] needs to
be filled, it is also guaranteed that all the cells which we scanned
just now (i.e. {in +X direction, all cells C[x][y][z], C[x+1][y][z],
C[x+2][y][z], ..., till the first filled cell}, similarly for -X, +Y,
-Y, +Z, -Z direction) must be part of the interior of some shape, and hence must be filled.
Another could be as follows :-
If for an unfilled cell C[x][y][z], we DO NOT encounter any filled
cell in, say, +X direction, then not only will C[x][y][z] remain
unfilled, it is also guaranteed that all the cells which we scanned
just now (i.e. in +X direction, all cells C[x][y][z], C[x+1][y][z],
C[x+2][y][z], ..., till the end of grid) must be part of the exterior
and hence, must remain unfilled.
Can someone suggest a more efficient approach to this problem? Even simple optimizations like above, which might not reduce the order of time complexity, are welcome.
You are dealing with 3D Flood Fill. See detailed Wikipedia article http://en.m.wikipedia.org/wiki/Flood_fill
Ok, as this is a closed hollow shapes, we can simply use a BFS or DFS to solve the problem.
BFS:
Starting with an empty queue, add to the queue any cell that lies inside the hollow shape. From the top of the queue, pop out one cell, fill this cell and check 6 other neighbors of this cell, if this neighbor is not filled, add it to the queue, else just ignore this cell. Continue this process until the queue is empty.
The remaining problem is to find a cell that located inside the hollow shape, one trick is the you need to find the cell located at the corner of the shape, which has at least three filled neighbors.
Time complexity is O(number of needed to filled cell * 6 direction need to check)
Tip to move to 6 direction:
int[] x = {0,0,0,0,1,-1};
int[] y = {0,0,1,-1,0,0};
int[] z = {1,-1,0,0,0,0};
Point p = // point in space with three dimension x,y,z
for(int i = 0; i < 6; i++){
int a = p.x + x[i];
int b = p.y + y[i];
int c = p.z + z[i];
}
For each cell, scan in the +X, -X, +Y, -Y, +Z, -Z direction, and see if you encounter a filled cell in each and every direction.
If a filled cell is encountered in each and every direction, then fill this cell (as it is part of the interior of some shape).
The above statement is incorrect unless you are only dealing with convex hulls. The image below shows that the point in question is not enclosed in the blue shape but it will still intersect in all (x,y,z) directions.
Instead, to handle the general case of finding hollowed shapes, you can add all cells to a Set. Then start at a boundary cell. The cell at the boundary is part of a hollowed shape if it is filled, otherwise it is part of a background (non-filled) shape.
Then, similar to #Pham Trung's answer, you can traverse outward in all directions until you have traversed all cells that are within the shape, ignoring the colored cells at the boundaries. Choose another cell at the boundary of the previous shape and start the process over until all cells are traversed.
In the end you will have each cell labeled as either part of a hollow shape or the background.
Just for completeness, two more. YMMV depending on a lot of factors.
1. Find the surface
If you are dealing with a large number of voxels, one optimisation possibility would be to find the border surface of the hollow. This can be done as in Pham Trung's answer but only accepting cells which have at least one of their 6 neighbours filled.
After the border surface has been determined, it can be filled line-by-line using 1D fills, as the directions "inside" and "outside" are known.
This method keeps the set size much smaller if you have a large number of voxels (scales as n^2 instead of n^3). Set lookups are usually very fast, but if the set does not fit into RAM, they slow down a lot.
2. Slice to 2D
Another possibility would be to slice the shape into 2D slices and connect the resulting cavities layer-by-layer. Then only two slices need to be kept in memory at the same time.
The principal idea is to give every separate connected 2D region an own identifier and then find its connections to the already known regions in the neighbouring layer. After handling all layers, connected 3D regions remain.
The challenging part is to find the best algorithm to connect the 2D regions in neighbouring layers. It seems that this method is fast with simple shapes (few disconnected regions in the 2D slices) but slow with complex shapes ("wormholes in tree"). Also, a quick algorithm to find a single common point in two sets is needed. (I.e. no full set intersection is required, just the information whether the sets have at least one common point or not.)
Again, if your sets are of reasonable size, the trivial algorithm described by Pham Trung is probably the best choice.

Random Tile layout

I need to place tiles on a large grid radiating from a central point in a way that looks organic and random. New tiles will need to find an open space on the grid that is touching at least 1 other tile.
Can anyone point me in the right to direction to anything that might help with this?
Or some basic concepts I can read up on that are in this vein?
For example, in this picture, there is a shape already created (yellow) and I may be receiving a new tile, that may be 1x1, 2x2, or 3x3. Trying to find a good way to figure out where I can place the new tile so that it will be touching the maximum amount of current tiles.
Picture:
alt text http://osomer.com/grid.JPG
Alternatively, you could approach this problem as the yellow tiles "eroding" away at the blue/background. To do this, at every step, have a yellow tile add a fixed number to the "erosion sum" E of all of the background tiles neighboring it in a cardinal direction (and perhaps maybe a fraction of that to the background tiles neighboring it diagonally).
Then, when it comes time to place a new tile, you can, for each background tile, pick a random number from 0 to E; the greatest one is "eroded" away. Alternatively, you could do a simple weighted random choice, with E being their weights.
For 2x2 or 3x3 tiles, you can pick only from tiles that suitably "fit" a 2x2 or 3x3 square in it (that is, a 2x2 or 3x3 the eroded tile on its edge, so that it doesn't cause overlap with already-placed tiles). But really, you're never going to get something looking as natural as one-by-one erosion/tile placement.
You can save time recalculating erosion sums by having them persist with each iteration, only, when you add a new tile, up the erosion sums of the ones around it (a simple +=). At this point, it is essentially the same as another answer suggested, albeit with a different perspective/philosophy.
A sample grid of Erosion Sums E, with direct cardinal neighbors being +4, and diagonal neighbors being +1:
Erosion Sums http://img199.imageshack.us/img199/4766/erosion.png
The ones with a higher E are most likely to be "eroded" away; for example, in this one, the two little inlets on the west and south faces are most likely to be eroded away by the yellow, followed by the smaller bays on the north and east faces. Least likely are the ones barely touching the yellow by one corner. You can decide which one either by assigning a random number from 0 to E for each tile and eroding the one with the highest random number, or doing a simple weighted random selection, or by any decision method of your choice.
For purely random, you start with an empty grid and a "candidate" list (also empty).
Place the first tile in the centre of the grid, then add each adjacent tile to the one you just placed into the "candidate" list. Then, each turn, choose a random entry in the "candidate" list and place a tile there. Look at each adjancent grid location next to where you just placed the tile, and for each one that is also empty, put it on the "candidate" list for the next time around (if not already there).
To avoid creating holes in your tile grid, increase the probability of selecting a grid location based on the number of adjacent tiles that are already filled (so if only one adjacent tile is already filled, it has low probably. If they're all filled, it'll have a very high probability).
In pseudo code:
grid = new array[width,height];
candidates = new list();
function place_tile(x,y) {
// place the tile at the given location
grid[x,y] = 1;
// loop through all the adjacent grid locations around the one
// we just placed
for(y1 = y - 1; y1 < y + 1; y1++) {
for(x1 = x - 1; x1 < x + 1; x1++) {
// if this location doesn't have a tile and isn't already in
// the candidate list, add it
if (grid[x,y] != 1 && !candidates.contains(x1,y1)) {
candidates.add(x1,y1);
}
}
}
}
// place the first tile in the centre
place_tile(width/2, height/2);
while (!finished) {
// choose a random tile from the candidate list
int index = rand(0, candidates.length - 1);
// place a tile at that location (remove the entry from
// the candidate list)
x, y = candidates[index];
candidates.remove(index);
place_tile(x, y);
}
The problem with your question is that 'organic and random' can be many different things.
Let me show two links
generating random fractal terrain (look at section 'Cloudy Skies' and imagine that you turn it to b/w, or in your case yellow/background).
simulating erosion (look at the image under 'erode')
The two above samples are 'organic and random' to me, but you might not be satisfied with those. So, I think you will have to better define what is 'organic and random'.
For now, I'll take your definition of the guiding rule for adding new tiles (but don't think it is necessarily the same problem), which I read as:
Given two shapes (assuming bitmaps)
find the relative position of the
shapes such that the number of
touching sides is maximum
I will also assume
overlap is not allowed
you can leave holes inside the resulting, merged shape
you can not rotate shapes
Under such conditions you need to test less then xy solutions and in each you need to
- discard it if there is an overlap
- discard it if they do not touch
- if they touch then count the number of edges that are common
All three of the above tests can be done in constant time by scanning all the yellow tiles (number of which is konstx*y)
So, the above can be easily done in O(n^4), is that good enough for you?
Compute a random spanning tree for the dual graph, that is, the grid whose vertices are the centers of your cells. For that, start at the center of the grid and do a random depth-first search. Then plot cells fro increasing tree distance from the center.

Packing rectangles for compact representation

I am looking for pointers to the solution of the following problem: I have a set of rectangles, whose height is known and x-positions also and I want to pack them in the more compact form. With a little drawing (where all rectangles are of the same width, but the width may vary in real life), i would like, instead of.
-r1-
-r2--
-r3--
-r4-
-r5--
something like.
-r1- -r3--
-r2-- -r4-
-r5--
All hints will be appreciated. I am not necessarily looking for "the" best solution.
Your problem is a simpler variant, but you might get some tips reading about heuristics developed for the "binpacking" problem. There has been a lot written about this, but this page is a good start.
Topcoder had a competition to solve the 3D version of this problem. The winner discussed his approach here, it might be an interesting read for you.
Are the rectangles all of the same height? If they are, and the problem is just which row to put each rectangle in, then the problem boils down to a series of constraints over all pairs of rectangles (X,Y) of the form "rectangle X cannot be in the same row as rectangle Y" when rectangle X overlaps in the x-direction with rectangle Y.
A 'greedy' algorithm for this sorts the rectangles from left to right, then assigns each rectangle in turn to the lowest-numbered row in which it fits. Because the rectangles are being processed from left to right, one only needs to worry about whether the left hand edge of the current rectangle will overlap any other rectangles, which simplifies the overlap detection algorithm somewhat.
I can't prove that this is gives the optimal solution, but on the other hand can't think of any counterexamples offhand either. Anyone?
Something like this?
Sort your collection of rectangles by x-position
write a method that checks which rectangles are present on a certain interval of the x-axis
Collection<Rectangle> overlaps (int startx, int endx, Collection<Rectangle> rects){
...
}
loop over the collection of rectangles
Collection<Rectangle> toDraw;
Collection<Rectangle> drawn;
foreach (Rectangle r in toDraw){
Collection<Rectangle> overlapping = overlaps (r.x, r.x+r.width, drawn);
int y = 0;
foreach(Rectangle overlapRect in overlapping){
y += overlapRect.height;
}
drawRectangle(y, Rectangle);
drawn.add(r);
}
Put a tetris-like game into you website. Generate the blocks that fall and the size of the play area based on your paramters. Award points to players based on the compactness (less free space = more points) of their design. Get your website visitors to perform the work for you.
I had worked on a problem like this before. The most intuitive picture is probably one where the large rectangles are on the bottom, and the smaller ones are on top, kinda like putting them all in a container and shaking it so the heavy ones fall to the bottom. So to accomplish this, first sort your array in order of decreasing area (or width) -- we will process the large items first and build the picture ground up.
Now the problem is to assign y-coordinates to a set of rectangles whose x-coordinates are given, if I understand you correctly.
Iterate over your array of rectangles. For each rectangle, initialize the rectangle's y-coordinate to 0. Then loop by increasing this rectangle's y-coordinate until it does not intersect with any of the previously placed rectangles (you need to keep track of which rectangles have been previously placed). Commit to the y-coordinate you just found, and continue on to process the next rectangle.

Resources