I am given an ordered set of points in 2D space as an output of a previous process. Coordinate points will be given in the form ((x0,y0),(x1,y1),...,(xn,yn)), where the very last coordinate pair will be a repetition of the first pair (i.e x0 = xn and y0 = yn). In this way, I know that when I re-encounter the same coordinate, I have made a closed loop. I would like to be able to detect the enclosed area by the polygon. If a single closed loop is given, the output should be the enclosed area of that closed loop. Now say I have a separate set of points, similar to to the first set. If a set of many closed looped polygons is given, then if each polygon is separated in space from each other, the output should be each enclosed area. However, if some of the polygons enclose each other, it should be the area bounded between both of them. For example, if I have one closed loop polygon inside another, the output area should between both of them (or in other words, the area enclosed by the larger one minus the area enclosed by the smaller one). If I have more than one closed loop polygon inside of a single larger one, it should be the area enclosed by the larger one minus all the areas enclosed by the smaller ones).
For a case where I have a region A enclosed by a region B, where B is enclosed by a region C, there are three distinct regions.
Region C minus region B (bounded on the outside by polygon 1)
Region B minus region A (bounded on the outside by polygon 2)
Region A (bounded on the outside by polygon 3)
Of the three regions, I only want region 1) and region 3). The reason I do not take region 2) is because for all the bounded areas on my 2D plane, the outermost polygons always represent the boundaries of a relevant region, and the input that produced my sets of coordinates representing my closed loop polygons would never have given me the points for polygon 2 if in the end region 1) and region 2) were meant to be combined. It instead would have given me only polygon 1 and polygon 3, similar to the case I described above.
In summary,
- I am given enough information to know all the coordinate points for a set of closed loop polygons on a 2D plane and they are distinguishable from each other.
- I need to develop an algorithm that will take in the entire set of closed loops polygons and return enough information to describe a bounded area. In thinking about the problem, I think the output that I would want is to know whether for a each and every line segment of the a closed loop polygon, on which side of that line segment is inside and outside of the polygon.
- It should be able to resolve the case where I have polygons inside of polygons.
- Closed loop polygons will never share any points. Each set of coordinate points will be unique to a polygon.
My initial thoughts were calculate the centroid of the polygon and then compare all line segments to the centroid, but I don't think this would work for all cases.
Judging by the description of your input, splitting your input stream into separate polygons is a trivial task.
After that, in order to "return enough information to describe a bounded area" you can build the following data structure out of your polygons:
Separate all polygons into two classes: main polygons and hole polygons.
Main polygon is... well, the exterior border of a bounded area. It separates the interior of the bounded area from the "outside world".
Hole polygon is a polygon that describes a hole in some main polygon.
Each hole polygon is associated with exactly one main polygon
Each main polygon is associated with zero or more hole polygons
Optionally, you can order the vertices in main polygons counterclockwise and vertices in hole polygons clockwise. But this is not strictly necessary to satisfy the formal requirement of "describing a bounded area"
The resulting structure is two-tiered: you end you with a list of main polygons, and each main polygon might contain a list of its holes.
In your example, you have 4 main polygons. One of them contains two hole polygons.
So, all you need to do is to recognize hole polygons and properly associate them with their main polygons.
An industrial-strength approach for solving this task would be an application of sweep-line algorithm to the input polygons. It would easily perform the classification into main and hole polygons as well as build the proper association between them.
An ad-hoc algorithm might look as follows
Sort all polygons in order of increasing area
For each polygon p in the sorted order
Take any vertex v of p
Perform an "inside" test of v against all polygons of greater area than p (for example, by using a simple even-odd intersection test: How can I determine whether a 2D Point is within a Polygon?)
If the number of polygons that contain v is odd, p is a hole polygon. Otherwise, p is a main polygon
If p is a hole polygon, then the smallest-area polygon that contains v is its associated main polygon.
That's it.
I think the output that I would want is to know whether for a each and every line segment of the a closed loop polygon, on which side of that line segment is inside and outside of the polygon.
Compute the normal for the line segment (perpendicular line).
Compute the mid-point of the line segment (any point will do).
Intersect every other line segment with a ray projected from the mid-point in the direction of the normal.
Intuitively, each intersection means either entering or exiting another polygon. Since finally the ray will be outside all polygons, we can deduce that if the ray intersects an even number of other line segments, then the side of the line segment indicated by the normal is on the outside of the polygon. If odd, it's on the inside.
There are a couple of tricky cases: one is where the ray exactly intersects the end-point of two connected line segments. Be careful to only count this as one intersection. The other case is where the ray is parallel to and exactly overlaps another line segment. This should count as two intersections.
There are more efficient algorithms (e.g. involving triangulation), but this one is simplest.
Related
This question is an extension on some computation details of this question.
Suppose one has a set of (potentially overlapping) circles, and one wishes to compute the area this set of circles covers. (For simplicity, one can assume some precomputation steps have been made, such as getting rid of circles included entirely in other circles, as well as that the circles induce one connected component.)
One way to do this is mentioned in Ants Aasma's and Timothy's Shields' answers, being that the area of overlapping circles is just a collection of circle slices and polygons, both of which the area is easy to compute.
The trouble I'm encountering however is the computation of these polygons. The nodes of the polygons (consisting of circle centers and "outer" intersection points) are easy enough to compute:
And at first I thought a simple algorithm of picking a random node and visiting neighbors in clockwise order would be sufficient, but this can result in the following "outer" polygon to be constructed, which is not part of the correct polygons.
So I thought of different approaches. A Breadth First Search to compute minimal cycles, but I think the previous counterexample can easily be modified so that this approach results in the "inner" polygon containing the hole (and which is thus not a correct polygon).
I was thinking of maybe running a Las Vegas style algorithm, taking random points and if said point is in an intersection of circles, try to compute the corresponding polygon. If such a polygon exists, remove circle centers and intersection points composing said polygon. Repeat until no circle centers or intersection points remain.
This would avoid ending up computing the "outer" polygon or the "inner" polygon, but would introduce new problems (outside of the potentially high running time) e.g. more than 2 circles intersecting in a single intersection point could remove said intersection point when computing one polygon, but would be necessary still for the next.
Ultimately, my question is: How to compute such polygons?
PS: As a bonus question for after having computed the polygons, how to know which angle to consider when computing the area of some circle slice, between theta and 2PI - theta?
Once we have the points of the polygons in the right order, computing the area is a not too difficult.
The way to achieve that is by exploiting planar duality. See the Wikipedia article on the doubly connected edge list representation for diagrams, but the gist is, given an oriented edge whose right face is inside a polygon, the next oriented edge in that polygon is the reverse direction of the previous oriented edge with the same head in clockwise order.
Hence we've reduced the problem to finding the oriented edges of the polygonal union and determining the correct order with respect to each head. We actually solve the latter problem first. Each intersection of disks gives rise to a quadrilateral. Let's call the centers C and D and the intersections A and B. Assume without loss of generality that the disk centered at C is not smaller than the disk centered at D. The interior angle formed by A→C←B is less than 180 degrees, so the signed area of that triangle is negative if and only if A→C precedes B→C in clockwise order around C, in turn if and only if B→D precedes A→D in clockwise order around D.
Now we determine which edges are actually polygon boundaries. For a particular disk, we have a bunch of angle intervals around its center from before (each sweeping out the clockwise sector from the first endpoint to the second). What we need amounts to a more complicated version of the common interview question of computing the union of segments. The usual sweep line algorithm that increases the cover count whenever it scans an opening endpoint and decreases the cover count whenever it scans a closing endpoint can be made to work here, with the adjustment that we need to initialize the count not to 0 but to the proper cover count of the starting angle.
There's a way to do all of this with no trigonometry, just subtraction and determinants and comparisons.
I have two polygons defined as a series of 2D floating point values. They are not guaranteed to be concave or convex. They do not cross over themselves. They cannot rotate. I want to place one randomly inside the other should it be possible based on it's size. The main problem is efficiency. I have to do this about 200 or so times in a few seconds.
I've been looking into this for a couple of days now, and have made no discernible headway. Any leads would be appreciated.
Disclaimer: If you are trying to pack multiple polygons inside a bigger polygon then I think, this problem is NP hard so it is unlikely that an efficient and exact algorithm can be developed to solve this problem. The polygon can continuously translate and rotate in a plane, which means the placements may be infinite and this makes the solution space of the problem also infinite. If you are just trying to find if the smaller polygon can fit inside the bigger one, I am short of an efficient answer, but as you have asked - "Any leads would be appreciated" - here is one.
Let the bigger polygon be B and smaller polygon (the one to be inserted) is S. B has a total of b points and S has a total of s points.
The image below shows a Bounding Box and a Minimum Bounding Rectangle. We use this to get the Fast Fail Filter (very simple idea... defined in next para). The box (a) shown below is faster to compute while box (b) is more accurate for filtering. Draw that box which gives better return on investment for your case. Though in the figure below they both are bounding an ellipse instead of a polygon but you get the idea.
(Image taken from: http://portal.ku.edu.tr/~cbasdogan/Tutorials/imageU21.JPG)
Crux: If any line of B intersects with any line of S, or if all lines of S are outside B, B cannot take S in.
Fast fail filter: Get the bounding rectangles of B and S. If you are not able to place the bounding rectangle of S inside the bounding rectangle of B, then you cannot place the polygon S inside polygon B. This way you fail faster if there is no chance of B to enclose S. Following image illustrates the three cases.
(Image taken from: http://www.cs.berkeley.edu/~ug/slide/pipeline/assignments/as4/figures/boundcull.gif)
Preprocessing: Determine the equation of lines that form B. Store them in a HashMap<<Point, Point>, Line> for a step that will be done later. You can uniquely define the line by slope m and intercept c and the end points of your line are going to be the key (<Point, Point>) of the HashMap.
The Algorithm:
For every S which has passed the above filter:
Read the points of S and determine the lines that form S
For every line of S, see if it intersects with any line of B† (they are stored in the HashMap already)
If there is no intersection, S is inside B and all you have to do is just draw the lines without any worry of intersection.
In the worst case, the complexity of this algorithm will be O(bs) for drawing each polygon.
†This step is written brute-force to keep the algo easy to understand. Otherwise a critical optimization that will give result faster is possible here. You can filter lines of B. You need not consider a line of B for intersection with S if the endpoints of the line of B are to the left of the leftmost point of S, or to the right of the rightmost point of S or above S or below S. This can save a lot of calculations.
If the other answer here is useful, this is an addendum to it. It shows another approach to see if smaller polygon is inside bigger one.
To test a polygon containment, you see if all the edges of the polygon are contained. To test all the edges, you test if all the points of every edge are contained.
Densify the smaller polygon by adding vertices between existing vertices. The image below shows densification of a line.
Now for the densified polygon, test if its points are all lying within the outer polygon. This test can be done by drawing lines from the point emanating to infinity on both sides and then counting how many times that line intersected with the bigger polygon.
If all points are within, then the polygon is within.
First Image source.
Second Image source.
I am trying to write C++ code to find the intersection points of a segment intersecting a tetrahedron. I reduced the problem like this:
For each face of the tetrahedron (a triangle), find the intersection point of the line segment. Then, I have three cases:
a) The segment doesn't intersect any face - thus either the segment is entirely in the tetrahedron or completely outside.
b) The segment only intersects one face. Then I just need to determine the side of the segment that is in the tetrahedron and I get the two points that are in the tetrahedron.
c) The segment intersects two faces.
I am having trouble implementing this algorithm. Here are the issues:
If the segment and triangle are in the same plane, how do I find the intersection points?
How can I determine if the segment lies on one of the edges of the tetrahedron?
Thanks.
Hint:
You can't avoid a complex case discussion. Here I introduce the planar case of a line segment and a triangle.
The sides of the triangle define three straight lines that partition the plane in 7 regions, one bounded and 6 unbounded. On the figure, they are designated by the signs obtained when you plug the coordinates of a point in the three implicit equations of these lines.
If you need to consider endpoints exactly on a side, you need to add 6 half-lines and 3 segments to the discussion.
Then take all possible combinations of the starting and ending regions.
Many of the cases are straightforward. When the two segment endpoint belong to the same region, the segment is wholly inside or outside; when one of the regions is +++ and the other is different, there is exactly one intersection...
In the case of the figure (--+ to ++-), you are sure to have one intersection with the bottom edge; but which is the other intersected side is unsure: to answer this, you need to tell on what side of the line segment the top vertex lies.
With some courage, you can discuss all 16 x 15 / 2 = 120 cases, many of which are identical to a permutation of the elements.
This is just an appetizer compared to the 3D problem.
"How can I determine if the segment lies on one of the edges of the tetrahedron?"
Write a function that computes the area of the triangle determined by three points in space. This can be computed from a determinant, as explained here and many other sites.
Then write a function that determines if two segments ab and cd are collinear.
They are if and only if the area of abc is zero, and the area of abd is zero.
Finally, write a function that determines if one point c lies on the segment ab. With all this, the remainder is easy.
To answer the general question, i.e. how to find the (up to two) intersections between a segment and a tetrahedron, I'd prefer to avoid the painful case-by-case analysis (mentioned in your problem reduction and in another answer).
I would use a variant of Sutherland-Hogdman's reentrant clipping (explained in 2D in [1]): the idea is to consider the tetrahedron as the intersection between four oriented half-spaces (limited by the support planes of the four faces of the tetrahedron).
Thus to compute the intersection between a segment and a tetrahedron, you can proceed as follows:
S := your segment
for f := 0 to 3 {
H := half_space(tet, f)
S := intersect(S, H)
}
H is just a plane equation (coefficients a,b,c,d of equation ax+by+cz+d=0,
[a,b,c] is the normal to the facet, oriented towards the interior of the tetrahedron. d is obtained by injecting a vertex incident to the facet into the equation).
The function intersect() is simple to implement (just test the sign of ax+by+cz+d at both vertices of the segment, if they differ, there is an intersection, that can be computed by injecting a parametric equation of S
x=x1+t(x2-x1), y=y1+t(y2-y1), z=z1+t(z2-z1) into (ax+by+cz+d=0) and solving for t, where (x1,y1,z1) and (x2,y2,z2) denote the two extremities of S.
In addition, the function intersect() may compute two booleans, to keep track of which vertex of S is a generated intersection.
[1] https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm
Does anyone know a relatively fast algorithm for decomposing a set of polygons into their distinct overlapping and non-overlapping regions, i.e. Given a set of n polygons, find all the distinct regions among them?
For instance, the input would be 4 polygons representing circles as shown below
and the output will be all polygons representing the distinct regions shown in the different colours.
I can write my own implementation using polygon operations but the algorithm will probably be slow and time consuming. I'm wondering if there's any optimised algorithm out there for this sort of problem.
Your problem in called the map overlay problem. It can be solved in O(n*log(n)+k*log(k)) time, where n is the number of segments and k is the number of segment intersections.
First you need to represent your polygons as a doubly connected edge list, different faces corresponding to the interiors of different polygons.
Then use the Bentley–Ottmann algorithm to find all segment intersections and rebuild the edge list. See: Computing the Overlay of Two Subdivisions or Subdivision representation and map overlay.
Finally, walk around each cycle in the edge list and collect faces of that cycle's half-edges. Every set of the faces will represent a distinct overlapping region.
See also: Shapefile Overlay Using a Doubly-Connected Edge List.
I don't think it is SO difficult.
I have answered the similar question on the friendly site and it was checked by a smaller community:
https://cs.stackexchange.com/questions/20039/detect-closed-shapes-formed-by-points/20247#20247
Let's look for a more common question - let's take curves instead of polygons. And let's allow them to go out of the picture border, but we'll count only for simple polygons that wholly belong to the picture.
find all intersections by checking all pairs of segments, belonging to different curves. Of course, filter them before real check for intersection.
Number all curves 1..n. Set some order of segments in them.
For every point create a sequence of intersections SOI, so: if it starts from the border end, SOI[1] is null. If not, SOI[1]= (number of the first curve it is intersecting with, the sign of the left movement on the intersecting curve). Go on, writing down into SOI every intersection - number of curve if there is some, or 0 if it is the intersection with the border.
Obviously, you are looking only for simple bordered areas, that have no curves inside.
Pieces of curves between two adjacent non-null intersection points we'll call segments.
Having SOI for each curve:
for segment of the curve 1, starting from the first point of the segment, make 2 attempts to draw a polygon of segments. It is 2 because you can go to 2 sides along the first intersecting curve.
For the right attempt, make only left turns, for the left attempt, make only the right turns.
If you arrive at point with no segment in the correct direction, the attempt fails. If you return to the curve 1, it success. You have a closed area.
Remember all successful attempts
Repeat this for all segments of curve 1
Repeat this for all other curves, checking all found areas against the already found ones. Two same adjacent segments is enough to consider areas equal.
How to find the orientation of the intersection.
When segment p(p1,p2) crosses segment q(q1,q2), we can count the vector multiplication of vectors pXq. We are interested in only sign of its Z coordinate - that is out of our plane. If it is +, q crosses p from left to right. If it is -, the q crosses p from right to left.
The Z coordinate of the vector multiplication is counted here as a determinant of matrix:
0 0 1
p2x-p1x p2y-p1y 0
q2x-q1x q2y-q1y 0
(of course, it could be written more simply, but it is a good memorization trick)
Of course, if you'll change all rights for lefts, nothing really changes in the algorithm as a whole.
I'm looking for a way to generate a set of random sided, but regular, polygons, inside a given rectangle or sector of a circle. To better explain, my given 2d space should have a random arrangement of regular polygons with various numbers of sides, so, e.g, if two hexagons are separated by a rectangle equal in length to their sides, the whole space cannot be filled with only more hexagons, some triangles may be required, etc.
I'm looking for one segment of a sort of kaleidoscope effect.
You are looking for tiling algorithms. See, for example, Penrose Tiler and Tilings and Tesselations pages for a start.
Another approach, I can think of:
First decide on how many objects you want. Say 'N'
Randomly Select 3 Points in your 2D Space.
Make use of 3 points to get a virtual triangle.
Now Select another point such a way that the point is outside the virtual triangle. Now form another virtual triangle by joining this point to 2 points from previous virtual triangle and then recurisevely form "N" virtual trianlges. Incase virtual triangles crossed, then you ignore the bigger trianlge and take triangles which had formed because of crossing points as new virtualtriangles
Now Generate a INSCRIBED Circle virtually to all virtual triangles which will never be able to intersect another virtual triangle since all virtual triangles are formed by without crossing any of the triangles as expalined above.
Make use of virtual circles to form any number of regular sides by dividing 360 degress to equal slices.
Now You can draw random regular polygons
I'm not sure I understand the requirements, but you can generate random regular polygons by randomly generating the following numbers:
radius (0 to whatever)
x and y of center (must be within radius of edges)
number of points (3 to whatever)
rotation (0 to 360)
To prevent overlapping, you can test each new polygon against each existing polygon and reject the new one if the distance between the centers is less than the sum of the radii.
Drawing the polygons is then a simple trig exercise.
See: "Heuristics for Generation of Random Polygons"
Generate N random points on a plane and extract the convex hull of the object (that is, if all polygons should be convex).
You can trivially reject before generating the convex hull if one of the points is inside another polygon. If it's not you still need to test the generated polygon against other polygons near it. (If you need to do this often, a spatial data structure is probably a something to look into).