Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!swrinde!zaphod.mps.ohio-state.edu!sdd.hp.com!uakari.primate.wisc.edu!dogie.macc.wisc.edu!decwrl!pacbell.com!pacbell!barn!everexn!roger From: roger@everexn.uucp (Roger House) Newsgroups: comp.graphics Subject: Re: Triangulating concave polygons Message-ID: <1990May29.212826.3457@everexn.uucp> Date: 29 May 90 21:28:26 GMT References: <807@fsu.scri.fsu.edu> Organization: Everex Systems, Inc. Lines: 245 In <807@fsu.scri.fsu.edu> prem@geomag.fsu.edu (Prem Subrahmanyam) writes: > I am presently writing a converter program between Aegis Modeller/ > VideoScape 3d format files to DBW_Render files. The one problem > I've encountered is that DBW has only triangles and parallelograms > as primitives, and I need to convert between possibly concave polygons > from Modeller to triangles. So far, this is what I've come up with > as a general algorithm: > 1. find a set of 3 points in a convex section of the polygon, and > slice these off as a triangle by drawing a line between the first > and third points. > 2. trianglulate the remaining part, according the the above until > you've boiled it down to a triangle--which is obviously pre-triangulated. > Question: how can I find 1. simply--I'd rather not try to map all the > points to a 2-dimensional coordinate system and test for insideness/ > outsideness by testing the intersection between a ray (of the Euclidean > type-not a CG ray) and the sides of the polygons by extending the ray in > any direction from the test point and determining how many lines it > hits--odd means inside, even means outside...I need a faster, dirtier > version that this. Any help will be much appreciated. > ---Prem Subrahmanyam It seems to me that projecting the original polygon to a 2-d situation is the way to go. However, after the projection, there is no need to check how many sides of the polygon are cut by a ray. It is not clear to me how the use of such a ray would help in decomposing into triangles. Following is a somewhat verbose description of a way to solve your problem, begin- ning with the 2-d case and then extending it to your 3-d problem. Concave or Convex? The cruz of your problem is determining whether an angle is convex (< 180 degrees) or not. Given three distinct points P0, P1, and P2 in the plane, how do we tell it the angle formed by line segments P0P1 and P1P2 is con- vex or not? Before we answer this, we must be clear about our point of view: We assume that we are ABOVE the xy-plane (i.e., at some point with a positive z-coordinate), looking down. In addition, we define the angle between P0P1 and P1P2 by measuring the arc swept out by rotating P1P2 about P1 in a COUNTERCLOCKWISE direction until we meet segment P0P1. We don't actually need to determine the exact angle. We simply want to know if it is < 180 degrees or not. Thus, we can conceptualize the pro- blem in a bit different way: Consider the infinite line oriented FROM P0 TO P1. Where is P2 in relation to this line? P2 is on the left: The angle is < 180 degrees P2 is on the line: The angle is = 180 degrees P2 is on the right: The angle is > 180 degrees So now the problem boils down to figuring out which side of a line that a point is on. This is easily determined. If L(x, y) = 0 is the ORIEN- TED equation of a line, where L(x, y) = ax + by + c, then for any point P, L(P) > 0: Point P is on the left of the line L(P) = 0: Point P is on the line L(P) < 0: Point P is on the right of the line Thus, to tell whether angle P0P1P2 is convex, do this: Determine the oriented equation of the line FROM P0 TO P1, and plug P2 into the equa- tion. If the result is > 0, then the angle is convex. WARNING: As always when working with floating point arithmetic, all comparisons should involve an epsilon. Furthermore, to be safe, the equation of the line should be normalized by dividing all coefficients by sqrt(a*a + b*b). Then when the equation is evalutated at a point, the result is actually the signed distance of the point from the line, which can be compared against an epsilon to see where the point is in relation to the line. A shortcut to the above method of determining a line equation is to use this determinant, where Ph = (xh, yh), Pi = (xi, yi), and Pj = (xj, yj): | xh yh 1 | D = | xi yi 1 | | xj yj 1 | If D > 0 then Pj lies on the left of the line FROM Ph TO Pi. If D = 0, the three points are collinear. If D < 0 then Pj lies on the right of the line FROM Ph TO Pi. (Lying on the left means angle PhPiPj is convex, and lying on the right means the angle is nonconvex.) DISCLAIMER: The above determinant should be checked. I am recalling it from memory, and it may not be quite right. Using this determinant is not really different from the method already de- scribed. Calculating the determinant is exactly the same as determining the equation of the line from point Ph to point Pi and then plugging Pj into the equation. Also, a warning is in order, because no normalization is done. So now we have a way to tell if an angle is convex or not. This operation is the basic primitive for all the following algorithms. Clockwise or Counterclockwise? Say we are given an array of n >= 3 distinct points labeled P0, P1, ..., Pn-1, which are the vertices of a well-formed simple polygon P. Say that the n vertices are in order, but we don't know if the order is clockwise or counterclockwise. How do we tell? Here is a simple algorithm: Scan the set of vertices and find the one with least x-coordinate. If there is more than one vertex with least x-coordinate, then pick the one of them which has least y-coordinate. The resulting vertex is unique. (If not, the polygon is ill-formed because its vertices are not distinct points.) Call this vertex Pi. Let Ph be the vertex preceding Pi, and let Pj be the vertex following Pi. Then test if angle PhPiPj is convex. If it is, then the vertices of poly- gon P are oriented counterclockwise in our input array. Otherwise, the vertices are ordered clockwise. In the latter case, reverse the elements of P to put the vertices in counterclockwise order. Decomposing a 2-d polygon in the xy-plane into triangles Given a well-formed simple polygon P with n >= 3 vertices labeled P0, P1, ..., Pn-1, we want to decompose P into triangles. We assume that the vertices are oriented in a counterclockwise direction as seen from above. Before presenting a general algorithm which handles all cases, it is worthwhile to consider the case when it is known that the polygon is convex (i.e., all angles < 180 degrees). Then the polygon is easily decomposed into n-2 triangles by drawing diagonals from vertex 0 to the n-3 vertices P2, P3, ..., Pn-2, resulting in these triangles: P0,P1,P2 P0,P2,P3 P0,P3,P4 . . . P0,Pn-2,Pn-1 If it is known that many of the polygons to be processed are likely to be convex, then it is a good idea to test each polygon to see if it is convex, and if so, apply the above simple algorithm. Only when a non- convex polygon is encountered is it necessary to apply the general al- gorithm. Here is the general algorithm: Let Pi be any vertex of the polygon. Let Ph be the vertex preceding Pi, and let Pj be the vertex following Pi. Test if angle PhPiPj is convex. If not, increment i, determine h and j from i, and test again. If a convex angle is not found by this process, there is an error in the polygon. It is either not well-formed, or it is oriented clockwise. Once a convex angle PhPiPj is found, the triangle formed by the three points is a candidate. However, it is ONLY a candidate. It must be tested like this: For every vertex V of the polygon other than the three forming the triangle, test if V is OUTSIDE the triangle (note that V must not be ON the boundary of the triangle). If some vertex is found which is either on the boundary of or inside of the triangle, then the triangle must be rejected. In this case, increment i and continue searching for a convex angle. If all V are outside of the triangle, then slice the triangle off the polygon by removing vertex Pi. If the number of points in the resulting polygon is 3, then the decomposition is finished. Otherwise, search again from a convex angle. Here is a more detailed version of the algorithm: i = n-1; while (n > 3) { h = i; i = (i == n-1 ? 0 : i+1); j = (i == n-1 ? 0 : i+1); if (angle PhPiPj nonconvex) continue; k = (j == n-1 ? 0 : j+1); /* k is vertex after j */ m = n-3; while (m--) if (Pk outside triangle PhPiPj) k = (k == n-1 ? 0 : k+1); else break; if (k != h) /* Vertex k not outside */ continue; /* triangle PhPiPj */ Store triangle PhPiPj; Remove vertex Pi from polygon P; n--; i = (i == 0 ? n-1 : i-1); } Store triangle P0P1P2 as the final triangle of the decomposition; The above algorithm always produces exactly n-2 triangles. Also, every vertex of every triangle produced by the algorithm is a vertex of the original polygon. In other words, no new points are created by this al- gorithm. Now Back to 3-Space Since your original problem has to do with a polygon in 3-space, we need to consider how to get from there to the xy-plane. Say that the input is an array Q of n >= 3 3-points, Q0, Q1, ..., Qn-1 which are the vertices of a well-formed simple planar polygon. If the plane of the polygon is not vertical (consider the xy-plane to be horizontal), then simply set up a 2-d polygon P with the points Q, ignor- ing the z-coordinate. In effect, this projects polygon Q onto the xy- plane. Now check if P is counterclockwise, and, if not, reverse its ele- ments so it is counterclockwise. Then decompose P into triangles. Note that if the z-coordinates are carried in polygon P (they will never be used because all algorithms above use only x- and y-coordinates), then the triangles produced by the decomposition will in fact be polygons in 3-space with correct z-coordinates. Thus, the input polygon is decom- posed as desired. If the input polygon is in a vertical plane (which can be determined by checking to see if the projection onto the xy-plane is a straight line), then simply swap the x- and z-coordinates of the input vertices, apply the algorithm in the preceding paragraph, and then swap the x- and z- coordinates of the resulting triangles. Note that this method of going from 3-space to 2-space works because a parallel projection of a polygon does not change any convex angles to nonconvex ones, or vice versa. Hope this helps.