Minimum area enclosing rectangles? - algorithm

I need an idea for an algorithm to solve the following problem (I already tried some personal
solutions but they don't seem to be optimal)
If given a surface with marked and unmarked zones (in matrix form), and 2 rectangles
that you can manipulate in any form or position, find the possible shape and position
of the rectangles such that they cover all the marked zones while keeping the minimum
surface area possible.

This answer is assuming you can not rotate the rectangles and the sides are always parallel to the x and y axis.
First, find the rectangle that encloses the complete area. An algorithm for that goes like this (assuming the origin is at the topleft):
For each marked spot in the matrix:
if spot.x < rectangle.left:
rectangle.left = spot.x
if spot.x > rectangle.right:
rectangle.left = spot.x
if spot.y < rectangle.top:
rectangle.left = spot.x
if spot.y < rectangle.bottom:
rectangle.left = spot.x
Then, find the largest horizontal gap like this:
largest_gap = -1
For each column in matrix:
last_marked_spot = 0, 0
For each spot in column:
if spot.marked:
if spot.x - last_marked_spot.x > largest_gap:
largest_gap = spot.x - last_marked_spot.x
last_marked_spot = spot
Same goes for vertical gap. Then check which gap is the biggest.
Then divide the all-including rectangle in two parts using the biggest gap as seperator. The final step is to collapse the two rectangles (using the reverse of the algorithm on the top).

Related

Finding two areas of a rectangle separated by a line

Given a rectangle and two points on the borders of the rectangle, where these two points will never share the same border, draw a line connecting these two points. Find the area of the two polygons formed by dividing the rectangle with this line. I am looking for an algorithm to find these two areas.
This seems like an easy problem but I couldn't find a consistent way to write the algorithm.
Here is an illustration of the problem with some example cases:
If we examine the 6 possible configurations we see that in all cases the area of one polygon is equal to half the area of the rectangle formed by the endpoints of the line (red), plus an additional rectangle (green) in the case where the line spans the width or height of the outer rectangle.
The area of one polygon is therefore given by:
r1, r2 : corner points of the rectangle
p1, p2 : endpoints of the line
area = abs(p1.x - p2.x) * abs(p1.y - p2.y) / 2
if abs(p1.x - p2.x) == abs(r1.x - r2.x)
area = area + abs(r1.x - r2.x) * (min(p1.y, p2.y) - min(r1.y, r2.y))
else if abs(p1.y - p2.y) == abs(r1.y - r2.y)
area = area + abs(r1.y - r2.y) * (min(p1.x, p2.x) - min(r1.x, r2.x))
Given two points of the straight line, you can pick the other two points from the corners of the rectangle to get the quadrilateral and then you could use the shoelace formula to compute the area of that quadrilateral.
If you find one quadrilateral area, you can find the other area just by subtracting first quadrilateral's area from the area of the whole rectangle.
There are 2 cases in total. Let say A and B are the number of corners on the left and right side of the red line, respectively.
Case 1: A = B = 2, then there are 2 trapezoids.
Case 2: A = 1 or B = 1, then there is at least 1 triangle.

Cover a polygonal line using the least given rectangles while keeping her continuity

Given a list of points forming a polygonal line, and both height and width of a rectangle, how can I find the number and positions of all rectangles needed to cover all the points?
The rectangles should be rotated and may overlap, but must follow the path of the polyline (A rectangle may contain multiple segments of the line, but each rectangle must contain a segment that is contiguous with the previous one.)
Do the intersections on the smallest side of the rectangle, when it is possible, would be much appreciated.
All the solutions I found so far were not clean, here is the result I get:
You should see that it gives a good render in near-flat cases, but overlaps too much in big curbs. One rectangle could clearly be removed if the previous were offset.
Actually, I put a rectangle centered at width/2 along the line and rotate it using convex hull and modified rotating calipers algorithms, and reiterate starting at the intersection point of the previous rectangle and the line.
You may observe that I took inspiration from the minimum oriented rectangle bounding box algorithm, for the orientation, but it doesn't include the cutting aspect, nor the fixed size.
Thanks for your help!
I modified k-means to solve this. It's not fast, it's not optimal, it's not guaranteed, but (IMHO) it's a good start.
There are two important modifications:
1- The distance measure
I used a Chebyshev-distance-inspired measure to see how far points are from each rectangle. To find distance from points to each rectangle, first I transformed all points to a new coordinate system, shifted to center of rectangle and rotated to its direction:
Then I used these transformed points to calculate distance:
d = max(2*abs(X)/w, 2*abs(Y)/h);
It will give equal values for all points that have same distance from each side of rectangle. The result will be less than 1.0 for points that lie inside rectangle. Now we can classify points to their closest rectangle.
2- Strategy for updating cluster centers
Each cluster center is a combination of C, center of rectangle, and a, its rotation angle. At each iteration, new set of points are assigned to a cluster. Here we have to find C and a so that rectangle covers maximum possible number of points. I don’t now if there is an analytical solution for that, but I used a statistical approach. I updated the C using weighted average of points, and used direction of first principal component of points to update a. I used results of proposed distance, powered by 500, as weight of each point in weighted average. It moves rectangle towards points that are located outside of it.
How to Find K
Initiate it with 1 and increase it till all distances from points to their corresponding rectangles become less than 1.0, meaning all points are inside a rectangle.
The results
Iterations 0, 10, 20, 30, 40, and 50 of updating cluster centers (rectangles):
Solution for test case 1:
Trying Ks: 2, 4, 6, 8, 10, and 12 for complete coverage:
Solution for test case 2:
P.M: I used parts of Chalous Road as data. It was fun downloading it from Google Maps. The I used technique described here to sample a set of equally spaced points.
It’s a little late and you’ve probably figured this out. But, I was free today and worked on the constraint reflected in your last edit (continuity of segments). As I said before in the comments, I suggest using a greedy algorithm. It’s composed of two parts:
A search algorithm that looks for furthermost point from an initial point (I used binary search algorithm), so that all points between them lie inside a rectangle of given w and h.
A repeated loop that finds best rectangle at each step and advances the initial point.
The pseudo code of them are like these respectively:
function getBestMBR( P, iFirst, w, h )
nP = length(P);
iStart = iFirst;
iEnd = nP;
while iStart <= iEnd
m = floor((iStart + iEnd) / 2);
MBR = getMBR(P[iFirst->m]);
if (MBR.w < w) & (MBR.h < h) {*}
iStart = m + 1;
iLast = m;
bestMBR = MBR;
else
iEnd = m - 1;
end
end
return bestMBR, iLast;
end
function getRectList( P, w, h )
nP = length(P);
rects = [];
iFirst = 1;
iLast = iFirst;
while iLast < nP
[bestMBR, iLast] = getBestMBR(P, iFirst, w, h);
rects.add(bestMBR.x, bestMBR.y, bestMBR.a];
iFirst = iLast;
end
return rects;
Solution for test case 1:
Solution for test case 2:
Just keep in mind that it’s not meant to find the optimal solution, but finds a sub-optimal one in a reasonable time. It’s greedy after all.
Another point is that you can improve this a little in order to decrease number of rectangles. As you can see in the line marked with (*), I kept resulting rectangle in direction of MBR (Minimum Bounding Rectangle), even though you can cover larger MBRs with rectangles of same w and h if you rotate the rectangle. (1) (2)

generate a random point within rectangles' areas uniformly (some rectangles could overlap)

Assume it's given a set of rectangles with different areas and some rectangles could overlap.
Objective is generating of a uniform random point among rectangles' areas.
Rectangle is defined as a pair of two points:
(x1,y1) - bottom leftmost corner;
(x2,y2) - top rightmost corner.
My strategy for uniform distribution of a random point among not overlapped rectangles is that,- randomly select a rectangle based on areas (existing solution):
for(int i = 0; i < rectangles.length; i++) {
int area = (rectangles[i].x2 - rectangles[i].x1) *
(rectangles[i].y1 - rectangles[i].y2);
if(rand.nextInt(total + area) >= total) {
selected = i;
break;
}
total += area;
}
Then generate an arbitrary point within a rectangle:
x1 +(1/(x2-x1))*rand(0,(x2-x1-1)),
y1 +(1/(y2-y1))*rand(0,(y2-y1-1)).
But how to be if some of rectangles could overlap?
Here is a simple and very fast solution if the first preprocessing step is fast enough (assumes rectangles are integer coordinates less than say.. 1000):
squares = set()
for rect in rects:
for oneByOneSquare in rect:
squares.add(oneByOneSquare)
squares = list(squares)
while True:
randomSquare = random.choice(squares)
randomPoint = randomPointInsideSquare(randomSquare)
The idea is to partition the rectangles into squares. Then randomly select squares and the randomly generate a point within that square.
An industrial-grade solution would be
Merge all rectangles into orthogonal polygons. These polygons do not overlap.
Decompose the polygons obtained at step 1 into non-overlapping rectangles.
Select your point uniformly in these non-overlapping rectangles.
This approach is applicable to any input of potentially overlapping polygons, if you replace the second step with any kind of triangulation (like trapezoidal decomposition followed by triangulation) and then select the point from the final set of triangles.

find all inner grid points of a polygon made up from neighbouring grid points

I have list of Points (int x, int y).
together they form areas, I check if this area is closed and then I need to get inner area formed by all positions that are inside this area.
example area:
Only idea I had is to convert this area to vector and check every point if it is inside polygon or not, counting intersections of polygon a axis's of point.
But I don't think it would be the most efficient way to do it.
other idea was to first get all points that are outside, I start from corners (if corner is not part of list of points, then is 100% empty), add all neighbor points that are empty and repeat.
then all points that aren't outside and aren't in highlighted list are inside.
but again, it feels somehow cumbersome...
To find all inner grid points of grid polygon, one can exploit these observations:
for each inner grid point (x,y) also (x,y+0.5) and (x,y-0.5) are inner points.
the lines defined by y=n+0.5 have simple intersections with the grid polygon
This leads to the following algorithm:
As a prerequisite one needs all non-horizontal (i.e. vertical and diagonal) polygon edges, actually only the x-coords of the centers in ascending order for each (second) mid-row.
The grid is scanned at each second horizontal "mid-line", i.e. y=2n+0.5, where n is from a sufficient range of integers s.t. the polygon is "covered", see the blue lines in the scetch.
Starting from the left all intersections with the polygon (i.e. the non-horizontal edges) and all inner points of the form (m,2n+0.5) are to be detected, see the red and green circles (this is done by iterating over the x-coors of the edges' centers)
Now the vertical grid neighbours (m,2n) and (m,2n+1) of inner points (m,2n+0.5) are inner points, if they are not on the boundary, see the green points in the scetch.
Here is some pseudo code (C++/python inspired :-) ):
list<Point> polygon; // given polygon as list of neighbouring grid points
// get centers of non-horizontal edges organized by line
map<int, set<float> > edgeCentersX; // for each scan line the x-coords of edges in ascending order
p_i = polygon[0]
yMin, yMax = 999999, -999999
for (i=1; i<polygon.size(); ++i)
p_i1 = polygon[i] // next point after p_i
if (p_i.x == p_i1.x)
continue // horizontal edges can be ignored
yMin_i = min(p_i.y, p_i1.y)
if (yMin_i % 2 == 1)
continue // we only need to look at each second mid-row
if (yMin_i < yMin)
yMin = yMin_i
if (yMin_i > yMax)
yMax = yMin_i
cx = 0.5*(p_i.x+p_i1.x)
edgeCentersX[yMin_i].insert(cx) // store edge center (yMin_i+0.5, cx)
p_i = p_i1
list<Point> innerPoints
for (y=yMin; y<= yMax; y+=2)
inside = false
cx_i = edgeCentersX[y][0]
for (i=1; i<edgeCentersX[y].size(); ++i)
cx_i1 = edgeCentersX[y][i]
inside = !inside
if (!inside)
continue
for (x=floor(cx_i)+1; x<cx_i1; ++x)
pLower = Point(y,x)
if (!polygon.contains(pLower))
innerPoints.append(pLower)
pUpper = Point(y+1,x)
if (!polygon.contains(pUpper))
innerPoints.append(pUpper)
Pick's theorem might be the formula you are looking for. It allows rather simple computation of the area for a polygon whose corners are grid points (i.e. have integer coordinates).

Fully cover a rectangle with minimum amount of fixed radius circles

I've had this problem for a few years. It was on an informatics contest in my town a while back. I failed to solve it, and my teacher failed to solve it. I haven't met anyone who was able to solve it. Nobody I know knows the right way to give the answer, so I decided to post it here:
Ze problem
Given a rectangle, X by Y, find the minimum amount of circles N with a fixed given radius R, necessary to fully cover every part of the rectangle.
I have thought of ways to solve it, but I have nothing definite. If each circle defines an inner rectangle, then R^2 = Wi^2 + Hi^2, where Wi and Hi are the width and height of the practical area covered by each circle i. At first I thought I should make Wi equal to Wj for any i=j, the same for H. That way, I could simplify the problem by making the width/height ratios equal with the main rectangle (Wi/Hi = X/Y). That way, N=X/Wi. But that solution is surely wrong in case X greatly exceeds Y or vice versa.
The second idea was that Wi=Hi for any given i. That way, squares fill space most efficiently. However if a very narrow strip remains, it's much more optimal to use rectangles to fill it, or better yet - use rectangles for the last row before that too.
Then I realized that none of the ideas are the optimal, since I can always find better ways of doing it. It will always be close to final, but not final.
Edit
In some cases (large rectangle) joining hexagons seem to be a better solution than joining squares.
Further Edit
Here's a comparison of 2 methods: clover vs hexagonal. Hexagonal is, obviously, better, for large surfaces. I do think however that when the rectangle is small enough, rectangular method may be more efficient. It's a hunch. Now, in the picture you see 14 circles on the left, and 13 circles on the right. Though the surface differs much greater (double) than one circle. It's because on the left they overlap less, thus waste less surface.
The questions still remain:
Is the regular hexagon pattern itself optimal? Or certain adjustments should be made in parts of the main rectangle.
Are there reasons not to use regular shapes as "ultimate solution"?
Does this question even have an answer? :)
For X and Y large compared to R, a hexagonal (honeycomb) pattern is near optimal. The distance between the centers of the circles in the X-direction is sqrt(3)*R. The distance between rows in the Y-direction is 3*R/2, so you need roughly X*Y/R^2 * 2*/(3*sqrt(3)) circles.
If you use a square pattern, the horizontal distance is larger (2*R), but the vertical distance is much smaller (R), so you'd need about X*Y/R^2 * 1/2 circles. Since 2/(3*sqrt(3) < 1/2, the hexagonal pattern is the better deal.
Note that this is only an approximation. It is usually possible to jiggle the regular pattern a bit to make something fit where the standard pattern wouldn't. This is especially true if X and Y are small compared to R.
In terms of your specific questions:
The hexagonal pattern is an optimal covering of the entire plane. With X and Y finite, I would think it is often possible to get a better result. The trivial example is when the height is less than the radius. In that case you can move the circles in the one row further apart until the distance between the intersecting points of every pair of circles equals Y.
Having a regular pattern imposes additional restrictions on the solution, and so the optimal solution under those restrictions may not be optimal with those restrictions removed. In general, somewhat irregular patterns may be better (see the page linked to by mbeckish).
The examples on that same page are all specific solutions. The solutions with more circles resemble the hexagonal pattern somewhat. Still, there does not appear to be a closed-form solution.
This site attacks the problem from a slightly different angle: Given n unit circles, what is the largest square they can cover?
As you can see, as the number of circles changes, so does the covering pattern.
For your problem, I believe this implies: different rectangle dimensions and circle sizes will dictate different optimal covering patterns.
The hexagon is better than the diamond. Consider the percent area of the unit circle covered by each:
#!/usr/bin/env ruby
include Math
def diamond
# The distance from the center to a corner is the radius.
# On a unit circle, that is 1.
radius = 1
# The edge of the nested diamond is the hypotenuse of a
# right triangle whose legs are both radii.
edge = sqrt(radius ** 2 + radius ** 2)
# The area of the diamond is the square of the edge
edge ** 2
end
def hexagon
# The hexagon is composed of 6 equilateral triangles.
# Since the inner edges go from the center to a hexagon
# corner, their length is the radius (1).
radius = 1
# The base and height of an equilateral triangle whose
# edge is 'radius'.
base = radius
height = sin(PI / 3) * radius
# The area of said triangle
triangle_area = 0.5 * base * height
# The area of the hexagon is 6 such triangles
triangle_area * 6
end
def circle
radius = 1
PI * radius ** 2
end
puts "diamond == #{sprintf "%2.2f", (100 * diamond / circle)}%"
puts "hexagon == #{sprintf "%2.2f", (100 * hexagon / circle)}%"
And
$ ./geometrons.rb
diamond == 63.66%
hexagon == 82.70%
Further, regular hexagons are highest-vertex polygon that form a regular tessellation of the plane.
According my calculations the right answer is:
D=2*R; X >= 2*D, Y >= 2*D,
N = ceil(X/D) + ceil(Y/D) + 2*ceil(X/D)*ceil(Y/D)
In particular case if the remainder for X/D and Y/D equal to 0, then
N = (X + Y + X*Y/R)/D
Case 1: R = 1, X = 2, Y = 2, then N = 4
Case 2: R = 1, X = 4, Y = 6, then N = 17
Case 3: R = 1, X = 5, Y = 7, then N = 31
Hope it helps.
When the circles are disposed as a clover with four leafs with a fifth circle in the middle, a circle will cover an area equal to R * 2 * R. In this arrangement, the question becomes: how many circles that cover an area of R * 2 * R will cover an area of W * H?, or N * R * 2 * R = W * H. So N = W * H / R * 2 * R.

Resources