Given the circle C: (O, r) and the polygon P, how can I find the smallest sector of C that covers P?
Assume that the radius of the circle is large enough, so the main problem is to find the initial and final angles of the sector.
I tried to draw rays from center of circle toward each of angles of the polygon and check if the ray overlaps the polygon. But there might be more than two rays that only touch the polygon. I can not rely on the selection of unique rays based on their direction angle, due to double precision. So finding min and max angles in the list of touched rays is useless. Beside that, I have problem with choosing either of sectors created by two terminal angles, since initial angle can be greater than final angle when computed by atan2
.
So what is the proper way to find such a sector?
Edit: Three example polygons (in WKT format):
POLYGON((52.87404 30.85613, 42.55699 28.46292, 41.54373 24.319989, 53.57623 21.300564, 62.94891 28.46292, 49.39652 27.550071, 52.87404 30.85613))
POLYGON((52.94294 30.920592, 42.55699 28.46292, 43.61965 35.545578, 55.85037 34.862696, 59.12524 36.621547, 47.68664 39.877048, 35.69973 36.198265, 37.30512 29.196711, 31.09762 28.46292, 41.54373 24.319989, 53.57623 21.300564, 62.94891 28.46292, 49.39652 27.550071, 52.94294 30.920592))
POLYGON((52.94294 30.920592, 42.55699 28.46292, 43.61965 35.545578, 52.45594 37.266299, 59.30560 29.196711, 64.12177 33.290489, 58.81733 36.554277, 47.68664 39.877048, 35.69973 36.198265, 37.30512 29.196711, 31.09762 28.46292, 41.54373 24.319989, 53.57623 21.300564, 62.94891 28.46292, 49.39652 27.550071, 52.94294 30.920592))
Center and radius of circle for all examples:
O: (45, 30)
r: 25
For starters we can handle your data as point cloud (polygon vertexes)
p[i]
and some circle defined by centerp0
and radiusr
. If your point cloud is entirely inside circle you can ignore the radius.We can exploit
atan2
however to avoid problems with crossing and sector selection we do not enlarge min/max bounds as usual for standard cartesian BBOX computation instead:compute
atan2
angle for each point and remember it in arraya[]
sort
a[]
find biggest distance between consequent angles in
a[]
Do not forget that angle difference can be
|Pi|
tops so if it is more you need to+/- 2*PI
. Also handlea[]
as cyclic buffer.This is my simple C++/VCL attempt:
You can ignore the
void TMain::draw()
function its just example of usage and this is the preview:However as you have polygon (lines) to avoid wrong results You have two simple options:
sample lines with more than just 2 points
this way the angular gap should be bigger than distances between points in the point cloud. So if you sample lines with enough points the result will be correct. However wrongly selected number of points per line will lead to wrong result in edge cases. On the other hand implementing this is just simple DDA interpolation added to current code.
convert to handling angle intervals instead of angles
a[]
so for each line compute angular interval
<a0,a1>
with predefined poygon winding rule (so CW or CCW but consistent). And instead of arraya[]
you would have ordered list of intervals where you would either insert new interval or merge with existing if overlap. This approach is safe but merging angular intervals is not that easy. If the input data is polyline (like yours) that means each next line start from the previous line endpoint so you can ignore the list of intervals and just enlarge the single one instead but still you need to handle the enlargement correctly which is not trivial.[Edit1] using the first approach the updated function look like this:
As you can see its almost the same just simple DDA is added to the first loop win
N
points per line. Here preview for the second polygon which fails with just point cloud approach: