Decomposition to Convex Polygons - geometry

This question is a little involved. I wrote an algorithm for breaking up a simple polygon into convex subpolygons, but now I'm having trouble proving that it's not optimal (i.e. minimal number of convex polygons using Steiner points (added vertices)). My prof is adamant that it can't be done with a greedy algorithm such as this one, but I can't think of a counterexample.
So, if anyone can prove my algorithm is suboptimal (or optimal), I would appreciate it.
The easiest way to explain my algorithm with pictures (these are from an older suboptimal version)
What my algorithm does, is extends the line segments around the point i across until it hits a point on the opposite edge.
If there is no vertex within this range, it creates a new one (the red point) and connects to that:
If there is one or more vertices in the range, it connects to the closest one. This usually produces a decomposition with the fewest number of convex polygons:
However, in some cases it can fail -- in the following figure, if it happens to connect the middle green line first, this will create an extra unneeded polygon. To this I propose double checking all the edges (diagonals) we've added, and check that they are all still necessary. If not, remove it:
In some cases, however, this is not enough. See this figure:
Replacing a-b and c-d with a-c would yield a better solution. In this scenario though, there's no edges to remove so this poses a problem. In this case I suggest an order of preference: when deciding which vertex to connect a reflex vertex to, it should choose the vertex with the highest priority:
lowest) closest vertex
med) closest reflex vertex
highest) closest reflex that is also in range when working backwards (hard to explain) --
In this figure, we can see that the reflex vertex 9 chose to connect to 12 (because it was closest), when it would have been better to connect to 5. Both vertices 5 and 12 are in the range as defined by the extended line segments 10-9 and 8-9, but vertex 5 should be given preference because 9 is within the range given by 4-5 and 6-5, but NOT in the range given by 13-12 and 11-12. i.e., the edge 9-12 elimates the reflex vertex at 9, but does NOT eliminate the reflex vertex at 12, but it CAN eliminate the reflex vertex at 5, so 5 should be given preference.
It is possible that the edge 5-12 will still exist with this modified version, but it can be removed during post-processing.
Are there any cases I've missed?
Pseudo-code (requested by John Feminella) -- this is missing the bits under Figures 3 and 5
assume vertices in `poly` are given in CCW order
let 'good reflex' (better term??) mean that if poly[i] is being compared with poly[j], then poly[i] is in the range given by the rays poly[j-1], poly[j] and poly[j+1], poly[j]
for each vertex poly[i]
if poly[i] is reflex
find the closest point of intersection given by the ray starting at poly[i-1] and extending in the direction of poly[i] (call this lower bound)
repeat for the ray given by poly[i+1], poly[i] (call this upper bound)
if there are no vertices along boundary of the polygon in the range given by the upper and lower bounds
create a new vertex exactly half way between the lower and upper bound points (lower and upper will lie on the same edge)
connect poly[i] to this new point
else
iterate along the vertices in the range given by the lower and upper bounds, for each vertex poly[j]
if poly[j] is a 'good reflex'
if no other good reflexes have been found
save it (overwrite any other vertex found)
else
if it is closer then the other good reflexes vertices, save it
else
if no good reflexes have been found and it is closer than the other vertices found, save it
connect poly[i] to the best candidate
repeat entire algorithm for both halves of the polygon that was just split
// no reflex vertices found, then `poly` is convex
save poly
Turns out there is one more case I didn't anticipate: [Figure 5]
My algorithm will attempt to connect vertex 1 to 4, unless I add another check to make sure it can. So I propose stuffing everything "in the range" onto a priority queue using the priority scheme I mentioned above, then take the highest priority one, check if it can connect, if not, pop it off and use the next. I think this makes my algorithm O(r n log n) if I optimize it right.
I've put together a website that loosely describes my findings. I tend to move stuff around, so get it while it's hot.

I believe the regular five pointed star (e.g. with alternating points having collinear segments) is the counterexample you seek.
Edit in response to comments
In light of my revised understanding, a revised answer: try an acute five pointed star (e.g. one with arms sufficiently narrow that only the three points comprising the arm opposite the reflex point you are working on are within the range considered "good reflex points"). At least working through it on paper it appears to give more than the optimal. However, a final reading of your code has me wondering: what do you mean by "closest" (i.e. closest to what)?
Note
Even though my answer was accepted, it isn't the counter example we initially thought. As #Mark points out in the comments, it goes from four to five at exactly the same time as the optimal does.
Flip-flop, flip flop
On further reflection, I think I was right after all. The optimal bound of four can be retained in a acute star by simply assuring that one pair of arms have collinear edges. But the algorithm finds five, even with the patch up.
I get this:
removing dead ImageShack link
When the optimal is this:
removing dead ImageShack link

I think your algorithm cannot be optimal because it makes no use of any measure of optimality. You use other metrics like 'closest' vertices, and checking for 'necessary' diagonals.
To drive a wedge between yours and an optimal algorithm, we need to exploit that gap by looking for shapes with close vertices which would decompose badly. For example (ignore the lines, I found this on the intertubenet):
concave polygon which forms a G or U shape http://avocado-cad.wiki.sourceforge.net/space/showimage/2007-03-19_-_convexize.png
You have no protection against the centre-most point being connected across the concave 'gap', which is external to the polygon.
Your algorithm is also quite complex, and may be overdoing it - just like complex code, you may find bugs in it because complex code makes complex assumptions.
Consider a more extensive initial stage to break the shape into more, simpler shapes - like triangles - and then an iterative or genetic algorithm to recombine them. You will need a stage like this to combine any unnecessary divisions between your convex polys anyway, and by then you may have limited your possible decompositions to only sub-optimal solutions.
At a guess something like:
decompose into triangles
non-deterministically generate a number of recombinations
calculate a quality metric (number of polys)
select the best x% of the recombinations
partially decompose each using triangles, and generate a new set of recombinations
repeat from 4 until some measure of convergence is reached

but vertex 5 should be given preference because 9 is within the range given by 4-5 and 6-5
What would you do if 4-5 and 6-5 were even more convex so that 9 didn't lie within their range? Then by your rules the proper thing to do would be to connect 9 to 12 because 12 is the closest reflex vertex, which would be suboptimal.

Found it :( They're actually quite obvious.
*dead imageshack img*
A four leaf clover will not be optimal if Steiner points are allowed... the red vertices could have been connected.
*dead imageshack img*
It won't even be optimal without Steiner points... 5 could be connected to 14, removing the need for 3-14, 3-12 AND 5-12. This could have been two polygons better! Ouch!

Related

How to determine whether an edge of a nonzero-fill polygon is an outside edge?

Let's assume I have a polygon and I have computed all of its self-intersections. How do I determine whether a specific edge is inside or outside according to the nonzero fill rule? By "outside edge" I mean an edge which lies between a filled region and a non-filled region.
Example:
On the left is an example polygon, filled according to the nonzero fill rule. On the right is the same polygon with its outside edges highlighted in red. I'm looking for an algorithm that, given the edges of the polygon and their intersections with each other, can mark each of the edges as either outside or inside.
Preferably, the solution should generalize to paths that are composed of e.g. Bezier curves.
[EDIT] two more examples to consider:
I've noticed that the "outside edge" that is enclosed within the shape must cross an even number of intersections before they get to the outside. The "non-outside edges" that are enclosed must cross an odd number of intersections.
You might try an algorithm like this
isOutside = true
edge = find first outside edge*
edge.IsOutside = isOutside
while (not got back to start) {
edge = next
if (gone over intersection)
isOutside = !isOutside
edge.IsOutside = isOutside
}
For example:
*I think that you can always find an outside edge by trying each line in turn: try extending it infinitely - if it does not cross another line then it should be on the outside. This seems intuitively true but I wonder if there are some pathological cases where you cannot find a start line using this rule. Using this method of finding the first line will not work with curves.
I think, you problem can be solved in two steps.
A triangulation of a source polygon with algorithm that supports self-intersecting polygons. Good start is Seidel algorithm. The section 5.2 of the linked PDF document describes self-intersecting polygons.
A merge triangles into the single polygon with algorithm that supports holes, i.e. Weiler-Atherton algorithm. This algorithm can be used for both the clipping and the merging, so you need it's "merging" case. Maybe you can simplify the algorithm, cause triangles form first step are not intersecting.
I realized this can be determined in a fairly simple way, using a slight modification of the standard routine that computes the winding number. It is conceptually similar to evaluating the winding both immediately to the left and immediately to the right of the target edge. Here is the algorithm for arbitrary curves, not just line segments:
Pick a point on the target segment. Ensure the Y derivative at that point is nonzero.
Subdivide the target segment at the Y roots of its derivative. In the next point, ignore the portion of the segment that contains the point you picked in step 1.
Determine the winding number at the point picked in 1. This can be done by casting a ray in the +X direction and seeing what intersects it, and in what direction. Intersections at points where Y component of derivative is positive are counted as +1. While doing this, ignore the Y-monotonic portion that contains the point you picked in step 1.
If the winding number is 0, we are done - this is definitely an outside edge. If it is nonzero and different than -1, 0 or 1, we are done - this is definitely an inside edge.
Inspect the derivative at the point picked in step 1. If intersection of the ray with that point would be counted as -1 and the winding number obtained in step 3 is +1, this is an outside edge; similarly for +1/-1 case. Otherwise this is an inside edge.
In essence, we are checking whether intersection of the ray with the target segment changes the winding number between zero and non-zero.
I'd suggest what I feel is a simpler implementation of your solution that has worked for me:
1. Pick ANY point on the target segment. (I arbitrarily pick the midpoint.)
2. Construct a ray from that point normal to the segment. (I use a left normal ray for a CW polygon and a right normal ray for a CCW polygon.)
3. Count the intersections of the ray with the polygon, ignoring the target segment itself. Here you can chose a NonZero winding rule [decrement for polygon segments crossing to the left (CCW) and increment for a crossing to the right (CW); where an inside edge yields a zero count] or an EvenOdd rule [count all crossings where an inside edge yields an odd count]. For line segments, crossing direction is determined with a simple left-or-right test for its start and end points. For arcs and curves it can be done with tangents at the intersection, an exercise for the reader.
My purpose for this analysis is to divide a self-intersecting polygon into an equivalent set of not self-intersecting polygons. To that end, it's useful to likewise analyze the ray in the opposite direction and sense if the original polygon would be filled there or not. This results in an inside/outside determination for BOTH sides of the segment, yielding four possible states. I suspect an OUTSIDE-OUTSIDE state might be valid only for a non-closed polygon, but for this analysis it might be desirable to temporarily close it. Segments with the same state can be collected into non-intersecting polygons by tracing their shared intersections. In some cases, such as with a pure fill, you might even decide to eliminate INSIDE-INSIDE polygons as redundant since they fill an already-filled space.
And thanks for your original solution!!

How do I check if a set of plane polygones create a watertight polyhedra

I am currently wondering if there is a common algorithm to check whether a set of plane polygones, not nescessarily triangles, contruct a watertight polyhedra. Each polygon has an oriantation (normal vector). A simple solution would just be to say yes or no. A more advanced version would be to point out the edges, where the polyhedron is "open". I am not really interesed on how to close to polyhedra.
I would like to point out, that my "holes" are not nescessarily small, e.g., one face of a cube might be missing. Thus, the "undersampling correction" algorithms dont seem to be the correct approach. Furthermore, I am talking of about 100 - 1000, not 1000000 polygons, so computation time should not really be a problem.
Any hints or tips?
kind regards,
curator
I believe you can use a simple topological test -- count the number of times each edge appears in the full list of polygons.
If the set of polygons define the surface of a closed volume, each edge should have count>=2, indicating that each edge is shared by (at least) two adjacent polygons. If the surface is manifold count==2 exactly.
Edges with count==1 indicate open regions of the surface.
The above answer does not cover many cases. A more correct (but not necessarily complete: I wouldn't know) algorithm is to ensure that every edge of every polygon (or of the mesh/polyhedron) has an even number of faces connected to it. Consider the following mesh:
The segment (line) between the closest vertex and the one below is attached to 3 faces (one one of the outer triangle and two of the inner triangle), which is greater than two faces. However this is clearly not closed.

"ray through vertex" special case when detecting point in polygon

To detect if a point is in a polygon, you project a line from the point, to infinity, and see how many of polygon's vertices it intersects with... simple enough. My problem is that if the ray intersects the polygon on one of the points, then it is counted as intersecting two segments, and considered outside the polygon. I altered my function to make it only count one of the segments when the ray intersects a point of the polygon, but there are cases where a line could intersect the point while still being outside as well. Take this image as an example:
If you assume the point in the top left is "infinity", and cast a ray to either of the other points, both intersect at a point of the polygon, and would count as intersecting the same number of vertices even though one is inside, and one is outside.
Is there a way to compensate for that, or do I just have to assume that those fringe cases won't pop up?
If the ray crosses a side exactly on a vertex, only count that side if the other vertex is above the ray. That will fix your corner case.
For example in the picture you posted, the lower ray crosses two sides of the square at the top-left vertex, but one side is above the ray and the other below, so that contributes 1 and the target point is found to be inside. The upper ray crosses two sides at the top-right vertex, both sides are below the ray, so they contribute 0 to the count and the target point is found to be outside.
Update:
I remembered reading an article which describes a technique for dealing with singular cases in general. Please read my other answer if interested.
While my first answer should do the trick for this simple problem, I can't help but mention that there exist general techniques for dealing with these kinds of special cases.
This article describes a technique for dealing with these kinds of issues in general. And one of the first examples they provide happens to be the algorithm you ask about!
The idea is to apply Automatic differentiation aka Dual numbers to compute symbolic perturbations.
By the way the same technique can also be used to avoid handling 0/0 as a special case in programs!
Here is the blog post I originally learned this from, it gives some great background to the technique, and the author blogs a lot about automatic differentiation (AD).
Despite appearances AD is a very practical technique especially in languages with good support for operator overloading (eg: C++, Haskell, Python ...) and I have used it in "real life" (industrial applications in C++).
Send ray in another direction.
If you try n+1 different directions (n is number of polygon points) one of them surely will not pass through any vertex.
This will simplify the code compared to consideration of corner cases.
Worst case becomes O(n)*CheckComplexity(n) which is likely O(n^2). If it's not acceptable, you can just sort all vertices by direction from the point to them and select middle of some interval. This will give O(n*log n).

Calculating the distance between each pair of a set of points

So I'm working on simulating a large number of n-dimensional particles, and I need to know the distance between every pair of points. Allowing for some error, and given the distance isn't relevant at all if exceeds some threshold, are there any good ways to accomplish this? I'm pretty sure if I want dist(A,C) and already know dist(A,B) and dist(B,C) I can bound it by [dist(A,B)-dist(B,C) , dist(A,B)+dist(B,C)], and then store the results in a sorted array, but I'd like to not reinvent the wheel if there's something better.
I don't think the number of dimensions should greatly affect the logic, but maybe for some solutions it will. Thanks in advance.
If the problem was simply about calculating the distances between all pairs, then it would be a O(n^2) problem without any chance for a better solution. However, you are saying that if the distance is greater than some threshold D, then you are not interested in it. This opens the opportunities for a better algorithm.
For example, in 2D case you can use the sweep-line technique. Sort your points lexicographically, first by y then by x. Then sweep the plane with a stripe of width D, bottom to top. As that stripe moves across the plane new points will enter the stripe through its top edge and exit it through its bottom edge. Active points (i.e. points currently inside the stripe) should be kept in some incrementally modifiable linear data structure sorted by their x coordinate.
Now, every time a new point enters the stripe, you have to check the currently active points to the left and to the right no farther than D (measured along the x axis). That's all.
The purpose of this algorithm (as it is typically the case with sweep-line approach) is to push the practical complexity away from O(n^2) and towards O(m), where m is the number of interactions we are actually interested in. Of course, the worst case performance will be O(n^2).
The above applies to 2-dimensional case. For n-dimensional case I'd say you'll be better off with a different technique. Some sort of space partitioning should work well here, i.e. to exploit the fact that if the distance between partitions is known to be greater than D, then there's no reason to consider the specific points in these partitions against each other.
If the distance beyond a certain threshold is not relevant, and this threshold is not too large, there are common techniques to make this more efficient: limit the search for neighbouring points using space-partitioning data structures. Possible options are:
Binning.
Trees: quadtrees(2d), kd-trees.
Binning with spatial hashing.
Also, since the distance from point A to point B is the same as distance from point B to point A, this distance should only be computed once. Thus, you should use the following loop:
for point i from 0 to n-1:
for point j from i+1 to n:
distance(point i, point j)
Combining these two techniques is very common for n-body simulation for example, where you have particles affect each other if they are close enough. Here are some fun examples of that in 2d: http://forum.openframeworks.cc/index.php?topic=2860.0
Here's a explanation of binning (and hashing): http://www.cs.cornell.edu/~bindel/class/cs5220-f11/notes/spatial.pdf

Looking for a fast polygon rendering algorithm

I am working with a Microchip dsPIC33FJ128GP802. It's a small DSP-based microcontroller, and it doesn't have much power (40 million instructions per second). I'm looking for a way to render a convex (i.e. simple) polygon. I am only dealing with 2D shapes, integer math, and set or clear pixels (i.e. 1 bit per pixel.) I already have routines for drawing fast horizontal and vertical lines (writing up to 16 pixels in 88 cycles), so I would like to use a scanline algorithm.
However, all the algorithms I have found seem to depend on division (which takes 18 cycles on this processor) and floating point math (which is emulated in software and so is very slow; it also takes up a lot of ROM), or assume that I have a large amount of memory. I only have 2K left, ~14K is used for graphics RAM of my 16K. So does anyone know of any good, embedded machine algorithms they can point me to with a simple C or pseudocode implementation which I can implement in assembly? Preferably on the 'net, I don't live near any good bookstores with many programming books.
Thanks. :)
EDIT: Clarification, this is a polygon filling algorithm I'm looking for. I can implement a polygon outline algorithm using Bresenham's line drawing algorithm (as Marc B suggests.)
EDIT #2: I wanted to let everyone know I got a basic algorithm up in Python. Here's a link to the code. Public domain code.
http://dl.dropbox.com/u/1134084/bresenham_demos.py
How about Bresenham's Line algorithm? After some setup, it's pure integer math, and can be adapted to draw a polygon by simple iteration of starting points along the polygon edges.
comments followup:
I'll try to draw this in ASCII, but it'll probably look like crud. Bresenham's can be used to draw a filled polygon by picking a starting edge, and iteratively moving a bresenham line across the canvas parallel to that point.
Let's say you've got some points like this:
*(1)
*(3)
*(2)
*(4)
These are numbered in left-right sort priority, so you pick the left-most starting point (1) and decide if you want to go vertically (start 1,2) or horizontally (1,3). That'd probably depend on how your DSP does its display, but let's go with vertical.
So... You use the 1-2 line as your starting bresenham line. You calculate the starting points of your fill lines by using lines 1-3 and 2-4 as your start/end points. Start a bresenham calculation for each, and draw another Bresenham between those two points. Kinda like:
1.1 -> 2.1, then 1.2 -> 2.2, then 1.3 -> 2.3
etc... until you reach the end of either of those lines. In this case, that'd be when the lower starting point reaches (4). At that point, you start iterating up the 4,3 line, until you reach point 3 with both starting points, and you're done.
*-------
\\\\\\\\ *
\\\\\\\\
*-----\\
------- *
Where the dashes are the starting points you calculated along 1-3 and 2-4, and the slashes are the fill lines.
Of course, this only works if the points are properly sorted, and you've got a convex polygon. If it's concave, you'll have to be very careful to not let your fill lines cross over the border, or do some pre-processing and subdivide the original poly into two or more convex ones.
You may want to look at Michael Abrash's articles on Dr Dobbs about polygon fill/raster/etc. It uses fixed-point math
Thomas, if you have a Bresenham line drawing algorithm available, then use it as a basis for further enhancement: divide your polygon to sub-polygons with an horizontal cutting line through every vertex. Then, start tracing the 2 left and right sides of each of these sub-polys, using Bresenham. This way you have the 2 end-points of each scan line in your polygon.
I would start by converting the polygon to a collection of triangles and render those, because triangles are easy to render by scanlines. Although even so there are some details.
Essentially, the draw-triangle sub-procedure will be given a raw triangle and proceed:
Reject degenerate triangles (where two of the three vertices overlap).
Sort the vertices in Y (since there are only three you can hardcode the sorting logic).
Now, at this point you should know that there will be three kinds of triangles: ones with a flat top, ones with a flat bottom, and "general" triangles. You want to handle a general triangle by essentially splitting it into one each of the flat types. This is because you don't want to have an if test every scanline to detect if the slope changed.
To render a flat triangle, you would run two Bresenham algorithms in parallel to iterate the pixels comprising the edges, and use the points they give you as the endpoints of each horizontal scanline.
It may be easier to break the problem into two parts. First, locate/write an algorithm that draws and fills a triangle. Second, write an algorithm that breaks up an arbitrary polygon into triangles (using different combinations of the vertices).
To draw/fill a triangle, use Bresenham's Line Algorithm to simultaneously draw a line between points 0 and 1, and between 1 and 2. For each input point x, draw the pixel if it is equal to or in between the y points generated by the two lines. When you reach one endpoint, continue by using the unfinished side and the side that has not yet been used.
Edit:
To break your convex polygon into triangles, arrange the points in order and call them P1, P2, ... PN. Let P1 be your "root" point, and build triangles using that point and combinations of adjacent points. For example, a pentagon would yield the three triangles P1-P2-P3, P1-P3-P4, and P1-P4-P5. In general, a convex polygon with N sides will decompose into N-2 triangles.

Resources