total area of intersecting rectangles - algorithm

What is an algorithm for determining the total area of two rectangles that are intersecting and may be rotated off the coordinate axes?

Here's roughly what you need to do, expressed as generally as possible, but covering all possibilities:
Work out the class of intersection. I.e. How many edges does the intersection area have? It could be anything from 0 to 8.
Find all vertices of the intersection. This will be all intersections between the edges of the rectangles, and associated corners of the rectangles themselves. Working this bit out is the most complex/tedious.
Work out the area of the intersection, by dividing it up into triangles if necessary.
Here's all the ways the rectangles can intersect:
Update
I've had some thoughts, and the best way to categorize the intersection is to trace round the perimeter of each rectangle and count the number of times each edge intersects another edge. You'll get a vector, e.g. for a six sided intersection area: {1,1,1,1},{0,1,1,1}, and for 8: {2,2,2,2},{2,2,2,2}. The two special cases you'll need to check for are when one rectangle completely encloses the other and when the edges are in line. You'll need to do careful checks, but this would be the starting point for a function to categorize the intersection.

Area(R1 union R2) = Area(R1) + Area(R2) - Area(R1 intersection R2), so you can calculate the area of the intersection to have the area of the union.
Intersections of two rectangles (or two convex polygons) are simple:
They are convex polygons
Their points are characterized as follows: intersection points of any pair of edges, and points of one rectangle which are inside the other.
So it goes like this:
L is an initially empty linked list
R1 has edges e1, e2, e3, e4, R2 has edges f1, f2, f3, f4. Compute intersection points of ei and fj, for all i,j=1,2,3,4. Add them to list L.
For each vertex v of R1, if v is inside R2, add it to L.
For each vertex w of R2, if w is inside R1, add it to L.
The convex hull of points in L is your intersection. As every point in L is on the boundary of the intersection, you can triangulate it and compute its area. Easy:
L = [x0, x1, ... ]
Sort points in L according to the angle of (xi - x0) with respect to an horizontal line passing through x0
First triangle is x0, x1, x2
Second triangle is x0, x2, x3
nth triangle is x0, x(n+1), x(n+2)
The area of a triangle is given by Heron formula:
a, b, c are edge lengths
s = 0.5 * (a + b + c)
area = sqrt(s * (s - a) * (s - b) * (s - c))
but beware of computing s - a, s - b and s - c independantly since you can encounter roundoff error (what if c ~ a and b << a for instance ?)

Ok, you have 3 possibilities:
1. Rectangles don't intersect
2. One rectangle is completely contained within the other (or they coincide)
3. The result of intersection is some convex polygon. You compute the area of a polygon by breaking it into triangles (by drawing segments from the first vertex to every other except for adjacent once). The you sum up the areas. You can use Herodot's theorem to calcaulate triangle's area and that's where midlle school geometry comes in.

Related

Algorithm to test if two line segments on a 2d grid are adjacent

Given two line segments on a 2D grid (horizontal or vertical), how can I determine if they are adjacent?
Two line segments A, B are adjacent if there exists at least one pair of points (ax, ay) in A and (bx, by) in B that are adjacent.
Two points are adjacent if they are adjacent in the horizontal or vertical direction. Diagonals do not count.
It can be assumed that the line segments do not intersect and the length is >= 1.
Clearly a naive solution would be to loop through the points and check for adjacency but I'm looking for a closed form solution in constant time.
For example these line segments are adjacent:
B
AB
AB
AB
B
as are these
A
ABBB
A
but these are not (note the space)
BBB
A
A
A
A horizontal or vertical line segment on a 2d grid can be represented as a tuple (x, y, length, vertical) where vertical is a boolean indicating the length of the line. Alternatively, such a line segment could be represented as (x0, y0, x1, y1) where either x0 = x1 or y0 = y1.
We can reduce this problem to computing the Manhattan distance between two axis-aligned rectangles.
The key observation is that the dimensions are separable, specifically, the Manhattan distance is the Manhattan distance of the x intervals (in 1D) plus the Manhattan distance of the y intervals.
The Manhattan distance between 1D intervals [a, b] and [c, d] is max(max(a, c) − min(b, d), 0).
The overall test is max(max(x0, x0′) − min(x1, x1′), 0) + max(max(y0, y0′) − min(y1, y1′), 0) = 1.
For any line the line itself and its adjacent (including diagonally) points form a rectangle as e.g.:
++++++ +++
+----+ +|+
++++++ +|+
+++
For a line (x0, y0, x1, y1) this rectangle is defined by the coordinates (x0 - 1, y0 - 1, x1 + 1, y1 + 1), let's name them (X0, Y0, X1, Y1). You now just need to check if these rectangles intersect:
A:X0 <= B:X1 and B:X0 <= A:X1
and A:Y0 <= B:Y1 and B:Y0 <= A:Y1
This yet includes diagonal adjacency, though, so you need to check this case explicitly:
A:X0 == B:X1
A:X1 == B:X0
A:Y0 == B:Y1
A:Y1 == B:Y0
Just count how many of these equations apply, if exactly two of do so (more is not possible...), then the rectangles only intersect in a pair of corners, thus the lines are only diagonally adjacent.

Efficient algorithm to find the largest rectangle from a set of points

I have an array of points, and my goal is to pick two so that I maximize the area of the rectangle formed by the two points (one representing the low left corner and the other one the right top corner).
I could do this in O(n^2) by just doing two for loops and calculating every single possible area, but I think there must be a more efficient solution:
max_area = 0
for p1 in points:
for p2 in points:
area = p2[0]p2[1] + p1[0]p1[1] - p2[1]p1[0] - p2[0]p1[1]
if area > max_area:
max_area = area
It's clear that I want to maximize the area of the second point with the origin (0,0) (so p2[0]p2[1]), but I'm not sure how to go forward with that.
Yes, there's an O(n log n)-time algorithm (that should be matched by an element distinctness lower bound).
It suffices to find, for each p1, the p2 with which it has the largest rectangular area, then return the overall largest. This can be expressed as a 3D extreme point problem: each p2 gives rise to a 3D point (p2[0], p2[1], p2[0] p2[1]), and each p1 gives rise to a 3D vector (-p1[0], -p1[1], 1), and we want to maximize the dot product (technically plus p1[0] p1[1], but this constant offset doesn't affect the answer). Then we "just" have to follow Kirkpatrick's 1983 construction.
Say you have a rectangle formed by four points: A (top left), B (top right), C (bottom right) and D (bottom left).
The idea is to find two points p1 and p2 that are the closest to B and D respectively. This means that p1 and p2 are the furthest possible from each other.
def nearest_point(origin, points):
nearest = None
mindist = dist(origin, points[0])
for p in points[1:]:
d = dist(origin, p)
if mindist > d:
mindist = d
nearest = p
return nearest
Call it for B and D as origins:
points = [...]
p1 = nearest_point(B, points) # one for loop
p2 = nearest_point(D, points) # one for loop
Note that there can be multiples closest points which are equally distant from the origin (B or D). In this case, nearest_point() should return an array of points. You have to do two nested for loops to find the furthest two points.
Divide and conquer.
Note: This algorithm presumes that the rectangle is axis-aligned.
Step 1: Bucket the points into a grid of 4x4 buckets. Some buckets
may get empty.
Step 2: Using the corners of the buckets, calculate
maximum areas by opposite corners between not empty buckets. This may result in
several pairs of buckets, because your work with corners, not points. Notice also that you use left corners for left buckets, and so for bottom, right, top corners for those b,r,t buckets. That's why an even number is used for the size of the grid.
Step 3: Re-bucket each bucket selected in step 2 as a new, smaller, 4x4 grid.
Repeat steps 2 & 3 until you get only a pair of buckets that contain only a point in each bucket.
I have not calculated the complexity of this algorithm. Seems O(n log(n)).

Calculate if circle fits inside of polygon (triangle/pentagon) given coordinates where touching the polygon is allowed? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 4 years ago.
Improve this question
Given a circle with center (Xc,Yc) and radius r
as well as a polygon with vertices inside of an array such that
vertices[] = { (Xv1, Yv1) , ... , (Xvn, Yvn) } where n is the number of vertices.
I want to be able to figure out if the circle is inside of the polygon. I am assuming (and it is safe to assume) that there are no holes in the polygon.
The only polygons I am checking will be triangles and pentagons.
What I have done so far is calculate if the center of the circle is inside of the polygon. This function is called isInside().
How can I check if the circle is completely inside of the polygons I am checking? Touching is ok.
More specifically, I am having trouble with the math for the relationship of the circle and the polygon which is crucial to solve this problem. I understand how to find if the center of the circle is inside the polygon, but not if the complete circle is contained in the polygon.
Anything helps :)
The following assumes you already know that the center of the circle is inside the polygon. There are a few things you want to check as your definition that touching the vertices is ok adds some cornercases. This solution works for concave polygons as well.
Early check
For the circle to be fully inside the polygon, we need all edges to be outside the circle. In particular this ensures that the polygon is not fully inside the circle.
Given the circle of radius r and centered at c and the edges e0, e1, ..., en of the polygon, a necessary condition is thus that for all i < n:
d(c, ei) >= r
where d is th euclidian distance.
If the above does not hold for any edge, then either there is an intersection between the polygon and the circle or the polygon is itself fully inside the circle.
Does the circle intersects the polygon
The last check is a necessary condition for the circle to be inside, although it is not sufficient as it is possible that all edges be outside the circle, but that the circle still leaks out of a vertice.
Let's first remember some formulas we will need.
Equation for a circle of radius r centred at (x0, y0):
(x - x0)2 + (y - y0)2 = r2
Thus the intersection with a line y = ax + b is found by solving:
(x - x0)2 + (ax + b - y0)2 = r2
This is nothing but a quadratic equation that can be rewritten as:
(a2 + 1)x2 + (2ab - 2ay0 - 2x0)x + (x0 + (b - y0)2 - r2) = 0
You can solve that with the quadratic formula for each vertex. You then have three possibilities.
1) There is no solution
This indicates there exists no intersection with this vertex. With high-level languages, you can catch some kind of MathError exception to detect that. Otherwise, you can mathematically check the sign of the discriminant as this case happens if it is negative.
(2ab - 2ay0 - 2x0)2 - 4 (a2 + 1) (x0 + (b - y0)2 - r2) < 0
2) There is a unique solution
If the equation has a single solution, that is both solution are the same, then the circle may touch, but does not leak out of the edge. You stated this is still considered to be inside the polygon in your case.
Mathematically, this happens when the discriminant is zero.
(2ab - 2ay0 - 2x0)2 - 4 (a2 + 1) (x0 + (b - y0)2 - r2) = 0
3) There exist two solutions
If there exist two solutions, say xi and xj, then there might be an overlap. Although, this is not certain in the case of concave polygons.
To check if there actually was an overlap, you must check if the intersection happens on your line segment.
This is quite simply done. Suppose your vertex lies between the points (x1, y1) and (x2, y2), then there is an intersection if an only if...
x1 < xi < x2
or...
x1 < xj < x2
In any other case, the intersection happens on the continuation of the vertex, not on the vertex itself.
If one of the above condition holds true, then and only then do you know that your circle leaks outside the polygon.
Final cornercase: concave edges
As stated, touching the polygon is ok, and thus there is a final cornercase not covered by the above: touching a concave edge.
A concave edge is an edge which inner angle is bigger than 180°. Thus whenever there is an intersection with the polygon, you want to ignore it if the intersection happens on an edge that is concave.
All of the above works for any polygon, not only triangles and hexagons.
Approach 1: simple, but NOT precise
You have already implemented an algorithm for checking whether a point is inside a polygon. So, why not just to approximate a circle as a equilateral polygon? You just check 16 or 64 or 256 points of the circle.
Approach 2: more complex, but IS precise
Find normal vector for each side of you polygon (you can easily calculate it).
Find distance from circle center to the side by this normal vector (lines intersection is a simple task too).
If the distance smaller than circle's radius, then the circle is outside the polygon.
Otherwise, if each side's distance to the point by it's normal is larger or equal to the circle's radius, then the circle is inside.

Find minimum number of triangles enclosing all points in the point cloud

Input
You have a points list which represents a 2D point cloud.
Output
You have to generate a list of triangles (should be as less as possible triangles) so the following restrictions are fulfilled:
Each point from the cloud should be a vertex of a triangle or be
inside a triangle.
Triangles can be build only on the points from
the original point cloud.
Triangles should not intersect with each
other.
One point of the cloud can be a vertex for several triangles.
If triangle vertex lies on the side of another triangle we assume such triangles do not intersect.
If point lies on the side of triangle we assume the point is inside a triangle.
For example
Investigation
I invented the way to find a convex hull of given set of points and divide that convex hull into triangles but it is not right solution.
Any guesses how to solve it?
Here is my opinion.
Create a Delaunay Triangulation of the point cloud.
Do a Mesh Simplification by Half Edge Collapse.
For step 1, the boundary of the triangulation will be the convex hull. You can also use a Constrained Delaunay Triangulation (CDT) if you need to honor a non-convex boundary.
For step 2 half-edge collapse operation is going to preserve existing vertices, so no new vertices will be added. Note that in your case the collapses are not removing vertices, they are only removing edges. Before applying an edge collapse you should check that you are not introducing triangle inversions (which produce self intersection) and that no point is outside a triangle. The order of collapses matter but you can follow the usual rule that measures the "cost" of collapses in terms of introducing poor quality triangles (i.e. triangles with acute angles). So you should choose collapses that produce the most isometric triangles as possible.
Edit:
The order of collapses guide the simplification to different results. It can be guided by other criteria than minimize acute angles. I think the most empty triangles can be minimized by choosing collapses that produce triangles most filled vs triangles most empty. Still all criteria are euristics.
Some musings about triangles and convex hulls
Ignoring any set with 2 or less points and 3 points gives always gives 1 triangle.
Make a convex hull.
Select any random internal point.
unless all points are in hull ...
All point in the hull must be part of an triangle as they per definition of convex hull can't be internal.
Now we have an upper bound of triangles, namely the number of points in the hull.
An upper bound is also number of points / 3 rounded up as you can make that many independent triangles.
so the upper bound is the minimum of the two above
We can also guess at the lower bound roundup(hull points / 3) as each 3 neighboring points can make a triangle and any surplus can reuse 1-2.
Now the difficult part reducing the upper bound
walk through the inner points using them as center for all triangles.
If any triangle is empty we can save a triangle by removing the hull edge.
if two or more adjacent triangles are empty we will have to keep every other triangle or join the 3 points to a new triangle, as the middle point can be left out.
note the best result.
Is this prof that no better result exist? no.
If there exist a triangle that envelop all remaining points that would this be better.
N = number of points
U = upper bound
L = lower bound
T = set of triangles
R = set of remaining points
A = set of all points
B = best solution
BestSolution(A)
if A < 3 return NoSolution
if A == 3 return A
if not Sorted(A) // O(N)
SortByX(A) // O(n lg n) or radex if possible O(N)
H = ConvexHull(A)
noneHull = A - H
B = HullTriangles(H, noneHull) // removing empty triangles
U = size B
if noneHull == 0
return U // make triangles of 3 successive points in H and add the remaining to the last
if U > Roundup(N/3)
U = Roundup(N/3)
B = MakeIndepenTriangles(A)
AddTriangle(empty, A)
return // B is best solution, size B is number of triangles.
AddTriangle(T, R)
if size T+1 >= U return // no reason to test if we just end up with another U solution
ForEach r in R // O(N)
ForEach p2 in A-r // O(N)
ForEach p3 in A-r-p2 // O(N)
t = Triangle(r, p2, p3)
c = Candidate(t, T, R)
if c < 0
return c+1 // found better solution
return 0
Candidate(t, T, R)
if not Overlap(t, T) // pt. 3, O(T), T < U
left = R-t
left -= ContainedPoints(t) // O(R) -> O(N)
if left is empty
u = U
U = size T + 1
B = T+t
return U-u // found better solution
return AddTriangle(T+t, left)
return 0
So ... total runtime ...
Candidate O(N)
AddTriangle O(N^3)
recursion is limited to the current best solution U
O((N N^3)^U) -> O((N^4)^U)
space is O(U N)
So reducing U before we go to brute force is essential.
- Reducing R quickly should reduce recursion
- so starting with bigger and hopefully more enclosing triangles would be good
- any 3 points in the hull should make some good candidates
- these split the remaining points in 3 parts which can be investigated independently
- treat each part as a hull where its 2 base points are part of a triangle but the 3rd is not in the set.
- if possible make this a BFS so we can select the most enclosing first
- space migth be a problem
- O(H U N)
- else start with points that are a 1/3 around the hull relative to each other first.
AddTriangle really sucks performance so how many triangles can we really make
Selecting 3 out of N is
N!/(N-3)!
And we don't care about order so
N!/(3!(N-3)!)
N!/(6(N-3)!)
N (N-1) (n-2) / 6
Which is still O(N^3) for the loops, but it makes us feel better. The loops might still be faster if the permutation takes too long.
AddTriangle(T, R)
if size T+1 >= U return // no reason to test if we just end up with another U solution
while t = LazySelectUnordered(3, R, A) // always select one from R first O(R (N-1)(N-2) / 6) aka O(N^3)
c = Candidate(t, T, R)
if c < 0
return c+1 // found better solution
return 0

Maximum surface inside a triangle

I have encountered the following interesting problem while preparing for a
contest.
You have a triangle with sides of length a, b, c and a rope of length L. You need to find
the surfaced enclosed by the rope that has the maximum surface area and it has to be entirely inside the triangle.
So, if L = a + b + c, then it's the area of the triangle.
Else, we know that the circle has the biggest surface to perimeter area, so if L is smaller or equal to the perimeter of the inscribed circle of the triangle, then the area will be the area of the circle of perimeter L.
So, the remaining case is alfa < L < a + b + c, where alfa is the perimeter of the inscribed circle .
Any ideas would be great!
EDIT: I would like to know if I should focus on some kind of algorithm for solving this
or trying to figure it out a mathematical formula. The contest contains somehow a combination of both. The edges can be as long as 100 and the precision of a,b,c,L is of 4 digits after the decimal point .
After reading the answers to this question: https://math.stackexchange.com/questions/4808/why-circle-encloses-largest-area, I agree with n.m., and think the optimal curve verifies:
Curvature is either constant, or flat when it touches the triangle, meaning it is composed of segments lying on the triangle sides, and circle arcs, all sharing the same radius.
There are no angles, meaning the arcs are tangent to the triangle sides.
With these conditions, the solution is obtained by three circles of same radius R, each tangent to two sides of the triangle (see below). When R varies between 0 and the radius of the inscribed circle, we start from the triangle itself, and end to the inscribed circle, where all three circles coincide. The length of the curve is the perimeter of the circle of radius R + the perimeter (p) of the smaller triangle: L = 2*PiR + p. The area is the area (a) of the smaller triangle + one disc of radius R + the remaining rectangles: A = PiR^2 + p*R + a.
Since a circle has the largest Area/Perimeter, start with the inscribed circle. If L is less than that circumference, then shrink appropriately. If L is longer, grow whichever of the 3 arcs maximizes dA/dL. I don't know if there's a closed form, but the largest arc will be in the 3rd of the triangle with the sides most approaching parallel.
It should be trivial to solve this algorithmically. With 4 decimals of precision, increment by 0.0001 checking each arc to see which has the greatest dA/dL for that single increment.
I worked up a drawing of the geometry overnight:
The inscribed circle is constructed by bisecting each of the angles and finding the intersections of the bisectors. I've labeled the half-angle "a1" (and all related variables have '1'). The area of the non-circular portion is two trapezoids (one denoted with the red outline). We can calculate the area for a single trapezoid as L1 * (m1 + R)/2 (note that when L1, L2, L3 are all zero, these trapezoids are all zero, and we just get the inscribed circle area). The circular cap has a radius of m1 to remain tangent with the side of the triangle. For a given choice of L1, m1 = R(x1-L1)/x1.
From here you can easily calculate the perimeter and area of each of the three sectors and solve numerically.
I cannot prove that this is the largest area, just that this is how to calculate the area and perimeter of this construction.
..answering my own comment/question, it can be proved that the radii must be equal,
Here is a useful formula:
the gray area A is
A = r^2 ( alpha - Pi + 2/tan(alpha/2) ) /2
but even more useful..the arc length is simply:
s = 2 ( b - A/r )
from here it is straightforward to show the three radii must be equal to each other:
writing the rope length and enclosed area:
ropelength = trianglelength - 2 Sum[r[i] a[i] ]
ropearea = trianglearea - Sum[r[i]^2 a[i] /2 ]
where
a[i]=( alpha[i] - Pi + 2/tan(alpha[i]/2) )
after a bit of manipulation maximizing the area leads to all r[i] equal. Note the three a[i], ropelength,trainglearea,trianglelength are all constants that you do not need to work out. Pedantically solve for r[l] = f( constants, r[2],r[3] ) sub into the second expression and solve for d ropearea /d r[2] = 0 and d /d r[3] = 0 with the result:
r =(1/2) (triangle_length - rope_length) /(Sum(1/tan(alpha[i]/2)) - Pi)
(the messy expression for a[i] is substituted only at the last step ) finally..
ropearea = trianglearea - (trianglelength-ropelength)^2/(8 Sum[a[i])
= trianglearea - (1/2)(trianglelength-ropelength) r
edit -- a useful identity ..with a,b,c, the lengths of the sides.
Sum(1/tan(alpha[i]/2)) = Sqrt( S^3 / ((S-a)(S-b)(S-c)) )
S = 1/2 (a+b+c) ! S is semiperimeter not to be confused with arc length s
the above expressions then can be used to reproduce the formula for an inscribed circle,
rinscribed = Sqrt( ((S-a)(S-b)(S-c)) / S )
If the perimeter of the rope is too small or too large, the answers are trivial. The interesting case is a shape with 6 vertices that goes line-arc-line-arc-line-arc. The arc are all tangent to their neighbouring lines and their radii are equal. I don't have a rigorous proof, but imagine a 2D balloon filled with air and squeezed between the sides of the triangle.
It is easy to express the overall shape and thus the perimeter given the radius; the opposite direction (perimeter to radius) is then easily found numerically.

Resources