Background and Theory

Polygon is one of the most important objects we are dealing with when we
rendering 2D/3D graphics or processing computational geometry. As a polygon
could be very complicated, some restrictions may be applied on implementation.
For example, OpenGL does not directly support drawing a concave polygon. When
you present OpenGL with a no convex filled polygon, it might not draw as you
expect. In most cases, we need to break down a complex polygon as its composed
simpler shapes, such as a set of triangles to simplify the problem.

In 1975, Gary Meisters developed the Two-Ears Theorem that proved this
attempt is always feasible: Except for triangles, every simple polygon has at
least two non-over lapping ears (triangles)[1].

A simple polygon is a polygon with no two non-consecutive edges intersecting.
If a diagonal (Pi-1, Pi+1) that bridges Pi lies entirely in the polygon, then
the vertex Pi is called an ear. To partitioning the polygon by finding ears, the
following lemma is also useful: If a convex vertex Pi is not an ear, then the
triangle formed by Pi-1, Pi, Pi+1 contains a concave vertex [2].

Figure 1. Polygon and Ears [3]

The following code present here demonstrates an O(kn) time algorithm for
finding ears and partitioning a simple polygon by triangles.

Figure 2. Polygon

Figure 3. Triangulated Polygon

Program Structure and Sample Code:

Based on Gary Meisters' theory, we always can find an ear from a polygon. If
we cut the ear from this polygon, we get a new polygon with one vertex less and
a triangle. Repeat this process with the new polygon till the polygon has only
three vertices left. The flowchart is as following:

Figure 4. Polygon Triangulation Program Flowchart

This program is written in C#.NET and developed with MS Visual Studio 2003.
To use object oriented program technology and make the code re-useable, I
structured the program with following classes:

Figure 5. Program Class Diagram

PolygonCuttingEarInterface Namespace:

The frmCuttingEars is the user interface where to receive the user-selected
polygon vertices, generate an object of CPolygonShape and pass the
data to the object, then retrieving the calculated data and presenting a serious
of triangles to the user.

PolygonCuttingEar Namespace:

The CpolygonShape is the class that does all the calculation:
find a polygon's ear, cut the ear by deleting the vertex and make an updated
polygon. This process will be repeated till the updated polygon is a
triangle.

Run the Program

To see a demonstration, first you select the way to initialize polygon
vertices: you can use the build-in testing data or pick up vertices by clicking
the panel, then draw polygon outer lines by clicking Draw Polygon button; Click
the Cut Ear button will start to triangulate the polygon, the triangles composed
the polygon will be colored on the screen.

To reset program for next demonstration, click the Clean Screen button, you
will be able to start over again.

You can use button, main menu, context menu or tool bar button to run the
program as your convenient. For assistance or more details of this program, you
can use the Help menu or reference the tool tip of each control by moving mouse
over the control.

Figure 6. User Selected Polygon

Figure 7. Triangulated Polygon

Please feel free to explore and use the source code here. If you have any
suggestions, please let me know and I will keep the code updated.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

This algorithm fails in most of the cases, Please provide a better solution for that. I am providing you a list of points where first coloumn is X, second is Y and last is Z.Use in -1 to +1 screen cordinate system.

I have used the triangulation library as part of a Extruded Shape -> OBJ converter to avoid uncontroled rendering efects. My polygons have holes and are potentially complex (no self intersection though). First I had to expand the library to include hole support (first merging the outer and inner hole with a fake double connection).

In general it worked fine, but some polygons were not correctly converted. Investigating I found out some methods where not giving the right response.

- VerticesDirection (in CPolygon) not always gives the right answer.-PointInsidePolygon from CPoint2D failed in some polygons.

I'm getting help from your codes here. Nice job! I'm wondering if I can get help with this problem. I'm trying to draw a simple concave polygon from a set of points(not sequential). Thanks in advance...

Holes are theoretically easy: Let the "hole" be a polygon with reverse winding inside of the containing polygon, and merge them into a single polygon by joining a vertex (actually a start and an end vertex with the same positions) from each polygon with two edges. Essentially you have one polygon with an infitesimal small gap, you can visualize it like: _________ / ___ \ | |___>---| \_________/(You'll have to copy and paste this ASCII *art* into some text editor with fixed-width font support, doesn't work with kerned fonts)Where the dashes represent the connecting seam, picture the outer polygon to be winded clockwise and the inner one counter clockwise.

Fiorentino, appreciate the response. I am trying to think of ways this could be implemented. I believe the original source code reversed the poly point hull if the points were deemed clockwise. So, I am not sure how this will play into having an outer poly point hull as clockwise. Would the point list be composed of one continuous point list (outer hull clockwise-inner hull anticlock)? I can try to play with some small samples to see the effect. Thanks

To be honest, I haven't read the original source code, but was eager to try to help you. Now, based on what you said about the source code ensuring the winding direction of the polygons, I assume this is because it makes the ear-clipping approach so much easier.If you encapsulate the polygon in a structure with a flag that says whether it is additive or subtractive (or hole or not hole or whatever lingo you prefer), you can then ensure the opposing winding directions of polygons that are supposed to be additive or subtractive (holes) in the method that ensures the proper winding directions.Then before the triangulation step, you map out what subtractive polygons are completely contained in what additive polygons (scrap overlapping polygons to make it easier, you can deal with edge intersections and clipping later on). You can do this by starting with a test on whether a vertex of the subtractive polygon is inside the additive polygon, if it is, then check that none of its edges intersect with the edges of the additive one. Of course, self-intersection would be tested for before this step to rule out all malshaped polygons.After this make the program find the closest vertices of the outer polygon and the hole polygon, and merge them there (this takes a bit of index magic, but is easy to do with a bit of thinking).Now, this should theoretically work for polygons with single holes. If there are multiple holes, and they do not overlap, inside of a polygon, you must take steps to ensure that the gluing edges do not cross any existing edges, so it's a bit more tricky.If done right, the newly constructed polygons from the holes should be consistent with the winding direction of the outer polygon, so the actual triangulation algorithm should need to be touched.Hope it works out for you. I've found that it isn't really possible to model a polygon with hole, without separating the two or joining them with a glue edge.

1. This for loop: for (int i= 1; i<nPoints; i++) needs to loop until i<=nPoints, that is: for (int i= 1; i<=nPoints; i++)

2. Points that are on the border will return inconsistent results. Since you are using the method of checking a line from the point and counting the number of intersections of polygon sides (even = outside, odd = inside). If the point is already on the a border of the polygon the code counts that as one intersection. depending on which side of the polygon the point is on and which way your testing line is drawn you may head into the poylgon, out the other side and cross another line resulting in 2 intersections (not in polygon). Or the testing line would be drawn away from the inner polygon resulting in just the one intersection (in the polygon). To fix this you can simply check if the point is on a border line and if it is return true, else continue with the test you now have.