Following Problem:
Let's say we have a rectangular map containing several rectangles.
I want to find all possible "maximal" rectangles which can be placed on the map without intersecting any of the other rectangles. With maximal I mean rectangles which can't be enlarged in any direction.
Does someone know an algorithm to perform this task?
enter image description here
I'll suggest a solution that may not be the faster but should do the job.
The idea is to place each of your rectangles one by one. Everytime you add a rectangle in the map, check if it intersects any of the others. If it does, then just break these both rectangles into the correct corresponding new rectangles, depending on the shape of the intersection.
It's easy to see that if a new rectangle (green) covers the whole affected rectangle (red), only the new would be broke apart. Otherwise, both will.
Just by adding one by one and breaking them apart correctly, you will have your full set of rectangles in the end, which you just need to iterate to find your "maximal", if it means the ones with biggest area.
This algorithm should be something around O(n²) where n is the number of rectangles you add.
You can do this with simple interval algebra. For illustration, I'll put some numbers on the example you gave us. I'll use the Cartesian first quadrant, origin in the lower-left corner. The entire field is then (0, 0) to (30, 20); rectangles have corners at (10, 0) to (30, 8); (0, 12) to (13, 20); (20, 15) to (25, 17).
To solve this, group rectangle edges by their orientation with respect to their rectangles; specifically, which direction they face (away from the rectangle's center). Edges of the window face inward. This gives us four sets, one for each "facing" direction. An edge is described with the common coordinate in one direction and a range in the other. I'll keep them in the same x-y notation. For instance, sorted by y-coordinate:
bottom low-rt up-rt
face_up = (0-10, 0), (10-30, 8), (20-25, 17)
The top edge of the top rectangle coincides with the top of the window; it faces up,. but has no room for a white rectangle.
Similarly, the down-facing edges are
up-left up-rt top
face_down = (0-13, 12), (20-25, 15), (13-30, 20)
Now it's a simple matter to match each rectangle edge with the first one that blocks its open region. For instance, consider the low-rt rectangle's face_up edge, (10-30, 8) We compare to face_down edges in order of y-coordinate, starting with y >= 8.
(0-13, 12) is the first y > 8 edge. Checking x intervals, we see that [0, 13] and [10-30] do overlap; we have a block with corners at (10, 8) and (12, 13) to expand sideways in each direction. This results in your blue rectangle.
Similarly, we will match the (face_up) left side of the window bottom with the same face_down edge. This results in your orange rectangle. Then we match the top of the up-rt (smallest) rectangle with the window top: green rectangle.
Continuing in the opposite direction, we find that two face_down edges match existing rectangles. We also match the bottom of the up-rt rectangle with the top of the low-rt rectangle, yielding the yellow rectangle.
Repeat this process with the face_left and face_right edges to obtain the red and purple rectangles, as well as a second hit of the orange rectangle.
Is that enough of an outline for you to implement?
Sorting the edges in order gives us the ability to do a linear search from each edge. If I'm casting this code properly, the result is an O(N) algorithm for N rectangles, although the original edge sorting is O(log N).
Related
I was wondering whether there is an algorithm for getting the coordinates of circles like on an Apple Watch.
I would like to have a function that I enter the number of circles I would like. Then it loops round the origin in a hexagonal fashion adding the circles. For example if I input 6 the following image is produced.
One way to do this would be to formulate this as a graph search problem. Imagine making a graph of hexagons, with the center hexagon at (0, 0). To find the positions of the n hexagons you want, run a BFS-like algorithm as follows:
Seed a queue with the point (0, 0), adding it to the list of points.
While fewer than n points have been generated:
Dequeue a point from the queue.
For each of its six hexagonal neighbors, if that point hasn’t yet been generated, generate it and add it to the queue.
The math of going from a hexagon to its neighbor is mostly trig; just move d units at 60n° for n = 0, 1, …, 5.
To ensure that you have things radiating out from the center, when visiting the neighbors or a point, consider sorting them clockwise or counterclockwise around the perimeter of the hexagon.
Points from (0,0) to (R,C) in the cartesian plane are colored r, g or b. Make a triangle using these points such that-
a) All three vertices are of different colors.
b) At least one side of triangle is parallel to either of the axes.
c) Area of the triangle is maximum possible.
Output the maximum possible area.
Constraints : 1<=R<=1000 , 1<=C<=1000
Can someone please let me know the approach to this question?
The area of a triangle is 1/2 * base * height. So if one side of the triangle is parallel to the
x-axis, then the base of the triangle is formed by two colors on the same row (spread as far apart as possible), and the third color should be on the row that's farthest from the base. Hence, you can preprocess the data to find:
the top-most and bottom-most row for each color
the left-most and right-most column for each color on every row
Then for every row, you have twelve possibilities for forming a triangle, e.g.
left-most-red, right-most-blue, top-most green
left-most-red, right-most-blue, bottom-most green
left-most-red, right-most-green, top-most blue
...
And of course, there's the corresponding process for triangles with one edge parallel to the y-axis.
Thus, the problem can be solved in O(R*C) time, where most of the time is spent in the preprocessing.
Given a polygon S and a point p that lies outside S, imagine an ant that can only follow a straight line towards or away from p.
For some shapes (Fig. 1), there is a choice of p such that the ant can move unobstructed in at least one of the two possibilities: towards (T) p, or away (A) from it. This condition corresponds to any ray cast from p intersecting the perimeter of S exactly 0 or 2 times.
However, for the same shape (Fig. 2) there may also be points that lead to blocked (B) regions, where the ant will bump into the polygon whichever direction it tries to move in. For yet other shapes (Fig. 3) there may be no choice of p that leads to no blocked regions. Having blocked regions corresponds to some rays cast from p that intersect the perimeter of S more than 2 times.
Is there an algorithm that determines whether a p exists that satisfies the condition for some given polygon S? If such points exist, can it also determine the region that contains them?
Find all concave corners of the polygon obstacle. For each corner, extend its two edges infinitely. The sector between these two rays, and also (as Nico Schertler pointed out) the point-reflected region of this sector, define where the point must be so that the obstacle does not hide the corner form the point's rays.
In the example with the L-shaped obstacle, there is one concave corner. The sector between its neighbouring edges (top right) and its point-reflection (bottom left), form a region (indicated in red), where the point must be.
In the example with the U-shaped obstacle, there are two concave corners, and the two corresponding regions (red and blue) have an overlap (purple). The point must be in this purple region.
In the example with the S-shaped obstacle, there are two overlapping regions (purple). The point must be in one of these two regions.
In the example with the H-shaped obstacle, the red and blue region have an overlap (purple) above the horizontal beam of the H, the blue and green region have an overlap (teal) to the right of the horizontal beam, the green and yellow region have an overlap (lime) below the horizontal beam, and the yellow and red regions have an overlap (orange) to the left of the beam; however, there is no overall overlap between the four regions, and no place where the point can be that will satisfy the constraints.
I have an axis alligned 3D box (cuboid), and a sphere at each of its vertices (each with different radius). How can I check if all points of the box are covered by any of the spheres?
I need an algorithm that is rather fast, and not necessarily exact.
False negatives -- that is saying that the box is not covered when in fact it is -- are not a big problem, but still I would like to minimise this kind of errors. False positives are unacceptable.
Intended use is calculating volume of an object specified by a signed distance function. I'm recursively dividing space and if a given box is completely outside or inside of the object, I know I can stop recursion on this level. False negative would cause extra splitting of the box, but not an error in the result.
(While I'm trying to find a geometrically optimal version, here's a simple idea that's sure to work, but it may return some false negatives.)
Consider two spheres at diagonally opposite corners of the box. Each of the spheres has 3 or more points where it intersects with the edges of the box. Seen from the opposite corner, one of these points is the furthest point inside the box on the sphere. That means that if all these points are covered by the opposite sphere, then the whole box is covered by these two spheres.
example 1: all points covered by diagonally opposite sphere
If the two spheres don't cover the whole box, check the other 3 pairs of diagonally opposite spheres. If one of the pairs covers the box, then it is covered by the 8 spheres. If none of the pairs covers the box, then it may or may not be covered by the 8 spheres (possible false negative).
example 2: some points not covered by diagonally opposite sphere
In the specific case of a cubic box, the radius of two diagonally opposite spheres which cover the whole cube with size 1 is given by these formulas:
0 ≤ ra ≤ 1 → rb ≥ √(2 + (1 - ra)2)
1 ≤ ra ≤ √2 → rb ≥ √(1 + (1 - √(ra2 - 1))2)
√2 ≤ ra ≤ √3 → rb ≥ 1 - √(ra2 - 2)
To avoid time-consuming calculations, using linear interpolation between a few points (including the breakpoints at 1 and √2) will give a conservative approximation. Or you can use the simpler but less precise approximation of ra2 + rb2 ≥ 3 (the blue circle on the graph below).
There is a similar method where you consider the 4 spheres around the bottom corners of the box, find the "landscape" their surfaces create inside the box, and then find the lowest point in this "landscape". If you then do the same for the top spheres, and the minimum heights of the two landscapes sum to more than the height of the box, then the box is covered by the spheres.
You can then also check the left/right and front/rear minimum heights to see whether they add up to the width and depth of the box. If any of them do, then the box is covered by the spheres. If none does, it is unsure whether the box is covered (possible false negative). Since this method considers all the spheres at once, I think it'll give fewer false negatives than the diagonally-opposite spheres method.
example 3a: finding the intersections of the 4 spheres
Seen from above, the intersection between any two spheres is the line between the two intersecting points of the circles where the spheres intersect the bottom side of the box.
example 3b: finding the lowest points on the intersections
The intersections between spheres join up to form the "valleys" in the "landscape". The highest point of a valley between two neighbouring spheres is at the edge of the box, the highest point of a valley between two diagonally opposite spheres is on the diagonal between their centers. So the lowest points are where the "valleys" meet. Which of these points is the lowest, is determined by their distance to the diagonal between the centers of the two largest spheres.
example 3c: side not completely covered
If some of the "valleys" don't meet, then part of the bottom side is not covered by these 4 spheres, and the minimum height is obviously zero.
I've been fiddling around with code for the minimum-height method, and the geometry needed to calculate the lowest point between 4 spheres is actually quite simple:
For the lowest point to be higher than zero, two diagonally opposed spheres need to intersect, i.e. ra+rc or rb+rd is not less than the box side's diagonal.
The height of a sphere with radius r above a point that is distance d away from the sphere's center is √r2-d2.
The part of a smaller sphere inside the box is completely contained within a larger sphere if the height of the larger sphere above the center point of the smaller sphere is greater than the smaller sphere's radius. The smaller sphere can then be ignored, because it has no impact on the height of the "landscape".
Two spheres a and b, whose centers are at a distance d from each other, intersect at a distance d2+ra2-rb2 / 2×d from the center of sphere a.
I think, due to the complexity of the problem, and since you accept false negatives, it would be a proper solution to just check if each sphere's radius is greater than half of the main diagonal (r*r > a*a + b*b + c*c). In this case, each sphere covers at least "its" 1/8 part of the cuboid and hence the cuboid is covered.
I have two 2D rectangles, defined as an origin (x,y) a size (height, width) and an angle of rotation (0-360°). I can guarantee that both rectangles are the same size.
I need to calculate the approximate area of intersection of these two rectangles.
The calculation does not need to be exact, although it can be. I will be comparing the result with other areas of intersection to determine the largest area of intersection in a set of rectangles, so it only needs to be accurate relative to other computations of the same algorithm.
I thought about using the area of the bounding box of the intersected region, but I'm having trouble getting the vertices of the intersected region because of all of the different possible cases:
I'm writing this program in Objective-C in the Cocoa framework, for what it's worth, so if anyone knows any shortcuts using NSBezierPath or something you're welcome to suggest that too.
To supplement the other answers, your problem is an instance of line clipping, a topic heavily studied in computer graphics, and for which there are many algorithms available.
If you rotate your coordinate system so that one rectangle has a horizontal edge, then the problem is exactly line clipping from there on.
You could start at the Wikipedia article on the topic, and investigate from there.
A simple algorithm that will give an approximate answer is sampling.
Divide one of your rectangles up into grids of small squares. For each intersection point, check if that point is inside the other rectangle. The number of points that lie inside the other rectangle will be a fairly good approximation to the area of the overlapping region. Increasing the density of points will increase the accuracy of the calculation, at the cost of performance.
In any case, computing the exact intersection polygon of two convex polygons is an easy task, since any convex polygon can be seen as an intersection of half-planes. "Sequential cutting" does the job.
Choose one rectangle (any) as the cutting rectangle. Iterate through the sides of the cutting rectangle, one by one. Cut the second rectangle by the line that contains the current side of the cutting rectangle and discard everything that lies in the "outer" half-plane.
Once you finish iterating through all cutting sides, what remains of the other rectangle is the result.
You can actually compute the exact area.
Make one polygon out of the two rectangles. See this question (especially this answer), or use the gpc library.
Find the area of this polygon. See here.
The shared area is
area of rectangle 1 + area of rectangle 2 - area of aggregated polygon
Take each line segment of each rectangle and see if they intersect. There will be several possibilities:
If none intersect - shared area is zero - unless all points of one are inside the other. In that case the shared area is the area of the smaller one.
a If two consecutive edges of one rectactangle intersect with a single edge of another rectangle, this forms a triangle. Compute its area.
b. If the edges are not consequtive, this forms a quadrilateral. Compute a line from two opposite corners of the quadrilateral, this makes two triangles. Compute the area of each and sum.
If two edges of one intersect with two edges of another, then you will have a quadrilateral. Compute as in 2b.
If each edge of one intersects with each edge of the other, you will have an octagon. Break it up into triangles ( e.g. draw a ray from one vertex to each other vertex to make 4 triangles )
#edit: I have a more general solution.
Check the special case in 1.
Then start with any intersecting vertex, and follow the edges from there to any other intersection point until you are back to the first intersecting vertex. This forms a convex polygon. draw a ray from the first vertex to each opposite vetex ( e.g. skip the vertex to the left and right. ) This will divide it into a bunch of triangles. compute the area for each and sum.
A brute-force-ish way:
take all points from the set of [corners of
rectangles] + [points of intersection of edges]
remove the points that are not inside or on the edge of both rectangles.
Now You have corners of intersection. Note that the intersection is convex.
sort the remaining points by angle between arbitrary point from the set, arbitrary other point, and the given point.
Now You have the points of intersection in order.
calculate area the usual way (by cross product)
.