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.
Related
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.
Assume you have a convex polygon P(defined by an array of points p), and a set of points S(all of them outside of P), how do you choose a point s in S such that it increases the most the area of P.
Example
I have a O(|P|) formula to calculate the area of the polygon, but I can't do this for every point in S given that
3 ≤ |P|, |S| ≤ 10^5
The big dots are the points in S
No 3 points in P u S are collinear
Given fixed points p = (px, py), q = (qx, qy) and a variable point s = (sx, sy), the signed area of the triangle ∆pqs is
|px py 1|
½ |qx qy 1|
|sx sy 1| ,
which is a linear polynomial in sx, sy.
One approach is to compute cumulative sums of these polynomials where p, q are the edges in clockwise order. Use binary search to find the sublist of edges that remain in the convex hull with a given point s, add the polynomials, and evaluate for s.
You have a method to calculate the exact area that is added by a point n (and David Eisenstat posted another), but their complexity depends on the number of sides of the polygon. Ideally you'd have a method that can quickly approximate the additional area, and you'd only have to run the exact method for a limited number of points.
As Paul pointed out in a comment, such an approximation should give a result that is consistently larger than the real value; this way, if the approximation tells you that a point adds less area than the current maximum (and with randomly ordered input this will be true for a large majority of points), you can discard it without needing the exact method.
The simplest method would be one where you only measure the distance from each point to one point in the polygon; this could be done e.g. like this:
Start by calculating the area of the polygon, and then find the smallest circle that contains the whole polygon, with center point c and radius r.
Then for each point n, calculate the distance d from n to c, and approximate the additional area as:
the triangle with area r × (d - r)
plus the rectangle with area 2 × r 2 (pre-calculated)
plus the half circle with area r × π (pre-calculated)
minus the area of the polygon (pre-calculated)
This area is indicated in blue on the image below, with the real additional area slightly darker and the excess area added by the approximation slightly lighter:
So for each point, you need to calculate a distance using √ ((xn - xc)2 + (yn - yc)2) and then multiply this distance by a constant and add a constant.
Of course, the precision of this approximation depends on how irregular the shape of the polygon is; if it does not resemble a circle at all, you may be better off creating a larger simple polygon (like a triangle or rectangle) that contains the original polygon, and use the precise method on the larger polygon as an approximation.
UPDATE
In a simple test where the polygon is a 1x1 square in the middle of a 100x100 square space, with 100,000 points randomly placed around it, the method described above reduces the number of calls to the precise measuring function from 100,000 to between 150 and 200, and between 10 and 20 of these calls result in a new maximum.
While writing the precise measuring function for the square I used in the test, I realised that using an axis-aligned rectangle instead of a circle around the polygon leads to a much simpler approximation method:
Create a rectangle around the polygon, with sides A and B and center point c, and calculate the areas of the rectangle and the polygon. Then, for each point n, the approximation of the additional area is the sum of:
the triangle with base A and height abs(yn - yc) - B/2
the triangle with base B and height abs(xn - xc) - A/2
the area of the rectangle minus the area of the polygon
(If the point is above, below or next to the rectangle, then one of the triangles has a height < 0, and only the other triangle is added.)
So the steps needed for the approximation are:
abs(xn - xc) × X + abs(yn - yc) × Y + Z
where X, Y and Z are constants, i.e. 2 subtractions, 2 additions, 2 multiplications and 2 absolute values. This is even simpler than the circle method, and a rectangle is also better suited for oblong polygons. The reduction in the number of calls to the precise measuring function should be similar to the test results mentioned above.
Recently I have started doing some research on the SAT (Separating Axis Theorem) for collision detection in a game I am making. I understand how the algorithm works and why it works, what I'm puzzled about is how it expects one to be able to so easily calculate the projection of the shape onto different axes.
I assume the projection of a polygon onto a vector is represented by line segment from point A to point B, so my best guess to find points A and B would be to find the angle of the line being projected onto and calculate the min and max x-values of the coordinates when the shape is rotated to the angle of the projection (i.e. such that it is parallel to the x-axis and the min and max values are simply the min and max values along the x-axis). But to do this for every projection would be a costly operation. Do any of you guys know a better solution, or could at least point me to a paper or document where a better solution is described?
Simple way to calculate the projection of the polygon on line is to calculate projection of all vertex onto the line and get the coordinates with min-max values like you suggested but you dont need to rotate the polygon to do so.
Here is algorithm to find projection of point on line :-
line : y = mx + c
point : (x1,y1)
projection is intersection of line perpendicular to given line and passing through (x1,y1)
perdenicular line :- y-y1 = -1/m(x-x1) slope of perpendicular line is -1/m
y = -1/m(x-x1) + y1
To find point of intersection solve the equation simultaneously :-
y = mx + c , y = -1/m(x-x1) + y1
mx + c = -1/m(x-x1) + y1
m^2*x + mc = x1-x + my1
(m^2+1)x = x1 + my1 - mc
x = (x1-my1 - mc)/(m^2+1)
y = mx + c = m(x1-my1-mc)/(m^2+1) + c
Time complexity : For each vertex it takes O(1) time so it is O(V) where V is no of vertex in the polygon
If your polygon is not convex, compute its convex hull first.
Given a convex polygon with n vertices, you can find its rotated minimum and maximum x-coordinate in n log n by binary search. You can always test whether a vertex is a minimum or a maximum by rotating an comparing it and the two adjacent vertices. Depending on the results of the comparison, you know whether to jump clockwise or counterclockwise. Jump by k vertices, each time decreasing k by half (at the start k=n/2).
This may or may not bring real speed improvement. If your typical polygon has a dozen or so vertices, it may make little sense to use binary search.
For 3 points in 2D :
P1(x1,y1),
P2(x2,y2),
P3(x3,y3)
I need to find a point P(x,y), such that the maximum of the manhattan distances
max(dist(P,P1),
dist(P,P2),
dist(P,P3))
will be minimal.
Any ideas about the algorithm?
I would really prefer an exact algorithm.
There is an exact, noniterative algorithm for the problem; as Knoothe pointed out, the Manhattan distance is rotationally equivalent to the Chebyshev distance, and P is trivially computable for the Chebyshev distance as the mean of the extreme coordinates.
The points reachable from P within the Manhattan distance x form a diamond around P. Therefore, we need to find the minimum diamond that encloses all points, and its center will be P.
If we rotate the coordinate system by 45 degrees, the diamond is a square. Therefore, the problem can be reduced to finding the smallest enclosing square of the points.
The center of a smallest enclosing square can be found as the center of the smallest enclosing rectangle (which is trivially computed as the max and min of the coordinates). There is an infinite number of smallest enclosing squares, since you can shift the center along the shorter edge of the minimum rectangle and still have a minimal enclosing square. For our purposes, we can simply use the one whose center coincides with the enclosing rectangle.
So, in algorithmic form:
Rotate and scale the coordinate system by assigning x' = x/sqrt(2) - y/sqrt(2), y' = x/sqrt(2) + y/sqrt(2)
Compute x'_c = (max(x'_i) + min(x'_i))/2, y'_c = (max(y'_i) + min(y'_i))/2
Rotate back with x_c = x'_c/sqrt(2) + y'_c/sqrt(2), y_c = - x'_c/sqrt(2) + y'_c/sqrt(2)
Then x_c and y_c give the coordinates of P.
If an approximate solution is okay, you could try a simple optimization algorithm. Here's an example, in Python
import random
def opt(*points):
best, dist = (0, 0), 99999999
for i in range(10000):
new = best[0] + random.gauss(0, .5), best[1] + random.gauss(0, .5)
dist_new = max(abs(new[0] - qx) + abs(new[1] - qy) for qx, qy in points)
if dist_new < dist:
best, dist = new, dist_new
print new, dist_new
return best, dist
Explanation: We start with the point (0, 0), or any other random point, and modify it a few thousand times, each time keeping the better of the new and the previously best point. Gradually, this will approximate the optimum.
Note that simply picking the mean or median of the three points, or solving for x and y independently does not work when minimizing the maximum manhattan distance. Counter-example: Consider the points (0,0), (0,20) and (10,10), or (0,0), (0,1) and (0,100). If we pick the mean of the most separated points, this would yield (10,5) for the first example, and if we take the median this would be (0,1) for the second example, which both have a higher maximum manhattan distance than the optimum.
Update: Looks like solving for x and y independently and taking the mean of the most distant points does in fact work, provided that one does some pre- and postprocessing, as pointed out by thiton.
How to design an algorithm to find minimum no.of sides of a polygon which lies between two concentric circles?
Similar to this:
Think about the simplest case first: the inner circle is microscopically small. The minimum number of sides is 3, as long as the inner circle has a non-zero radius.
When does the polygon start needing 4 sides? Draw an equilateral triangle inscribed in the circle. The polygon starts needing 4 sides when the inner circle's radius reaches the center point of the sides of the triangle.
If you inscribe a regular polygon of N sides into the outer circle, you can compute the distance from the midpoint of each side to the center of the circle using the cosine rule:
distance_to_midpoint = cos ( 360 / (N * 2) ) * radius_of_outer_circle
(Explanation: if you make a isosceles triangle using the center point of the circle to the side in question, the radii have an angle of 360 / N. Divide the triangle in half at the side's midpoint to form a right-angle triangle with hypotenuse equal to the radius of the outer circle, then use cosine rule)
Now distance_to_midpoint needs to be greater than or equal to the radius of the inner circle, so solve for N:
radius_of_inner_circle = cos(360 / (N * 2)) * radius_of_outer_circle
cos(360 / (N*2)) = radius_of_inner_circle / radius_of_outer_circle
360 / (N*2) = acos(radius_i / radius_o)
N = 180 / (acos(radius_i / radius_o))
(I haven't double checked this math, and it's really late).
Denote the radius of the polygon, which is the radius of the circumcircle of the polygon, by R. The radius of the inscribed circle is
r = R*Cos[180°/n]
Solve this for n, eliminate the spurious solution which gives a negative result, and you have
n = 180°/ArcCos[r/R]
You'll have to fiddle around a bit to get an integer value for n, I'll leave that to you.
Draw a tangent to the inner circle, mark A, B - intersections of the tangent with the outer circle.
Draw a tangent (different) to the inner circle from point B, mark the intersection with outer circle C.
Repeat the procedure (2) until the new tangent crosses first tangent AB.
This algorithm will ensure you cover the maximum radial section at each step, thus minimizing the number of sides in the resulting polygon.
If you only want to find number of sides, it's enough to find an angle between 2 tangents to the inner circle coming from the same point on the outer circle and calculate how many such angles comprise the full 360 degrees (add 1 if there is a remainder) - like #cheeken suggested in comment