ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/triangulate.c
Revision: 2.4
Committed: Thu Dec 22 18:48:36 2016 UTC (7 years, 4 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.3: +14 -6 lines
Log Message:
Fixes from Nathaniel Jones for co-linear vertices and seams/holes

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.4 static const char RCSid[] = "$Id$";
3 greg 2.1 #endif
4     /*
5     * triangulate.c
6     *
7     * Adapted by Greg Ward on 1/23/14.
8     * Copyright 2014 Anyhere Software. All rights reserved.
9     *
10     */
11    
12     /* COTD Entry submitted by John W. Ratcliff [[email protected]]
13    
14     // ** THIS IS A CODE SNIPPET WHICH WILL EFFICIEINTLY TRIANGULATE ANY
15     // ** POLYGON/CONTOUR (without holes) AS A STATIC CLASS. THIS SNIPPET
16     // ** IS COMPRISED OF 3 FILES, TRIANGULATE.H, THE HEADER FILE FOR THE
17     // ** TRIANGULATE BASE CLASS, TRIANGULATE.CPP, THE IMPLEMENTATION OF
18     // ** THE TRIANGULATE BASE CLASS, AND TEST.CPP, A SMALL TEST PROGRAM
19     // ** DEMONSTRATING THE USAGE OF THE TRIANGULATOR. THE TRIANGULATE
20     // ** BASE CLASS ALSO PROVIDES TWO USEFUL HELPER METHODS, ONE WHICH
21     // ** COMPUTES THE AREA OF A POLYGON, AND ANOTHER WHICH DOES AN EFFICENT
22     // ** POINT IN A TRIANGLE TEST.
23     // ** SUBMITTED BY JOHN W. RATCLIFF ([email protected]) July 22, 2000
24     */
25    
26     #include <stdio.h>
27     #include <stdlib.h>
28     #include "triangulate.h"
29    
30     #ifndef true
31     #define true 1
32     #define false 0
33     #endif
34    
35     static const double EPSILON = 0.0000000001;
36    
37     static int
38     polySnip(const Vert2_list *contour, int u, int v, int w, int n, int *V)
39     {
40     int p;
41 greg 2.4 double Ax, Ay, Bx, By, Cx, Cy, Px, Py, cross;
42 greg 2.1
43     Ax = contour->v[V[u]].mX;
44     Ay = contour->v[V[u]].mY;
45    
46     Bx = contour->v[V[v]].mX;
47     By = contour->v[V[v]].mY;
48    
49     Cx = contour->v[V[w]].mX;
50     Cy = contour->v[V[w]].mY;
51    
52 greg 2.4 cross = ((Bx - Ax)*(Cy - Ay)) - ((By - Ay)*(Cx - Ax));
53     if (EPSILON > cross) return EPSILON > -cross ? -1 : false; /* Negative if colinear points */
54 greg 2.1
55     for (p=0;p<n;p++)
56     {
57 greg 2.3 if( (p == u) | (p == v) | (p == w) ) continue;
58 greg 2.1 Px = contour->v[V[p]].mX;
59     Py = contour->v[V[p]].mY;
60 greg 2.4 if ((Px == Ax && Py == Ay) || (Px == Bx && Py == By) ||
61     (Px == Cx && Py == Cy)) continue; /* Handle donuts */
62 greg 2.1 if (insideTriangle(Ax,Ay,Bx,By,Cx,Cy,Px,Py)) return false;
63     }
64    
65     return true;
66     }
67    
68     Vert2_list *
69     polyAlloc(int nv)
70     {
71     Vert2_list *pnew;
72    
73     if (nv < 3) return NULL;
74    
75     pnew = (Vert2_list *)malloc(sizeof(Vert2_list) + sizeof(Vert2)*(nv-3));
76     if (pnew == NULL) return NULL;
77     pnew->nv = nv;
78     pnew->p = NULL;
79    
80     return pnew;
81     }
82    
83     double
84     polyArea(const Vert2_list *contour)
85     {
86     double A=0.0;
87     int p, q;
88    
89     for(p = contour->nv-1, q = 0; q < contour->nv; p=q++)
90     {
91     A += contour->v[p].mX*contour->v[q].mY - contour->v[q].mX*contour->v[p].mY;
92     }
93     return A*0.5;
94     }
95    
96     /*
97     InsideTriangle decides if a point P is Inside of the triangle
98     defined by A, B, C.
99     */
100     int
101     insideTriangle(double Ax, double Ay,
102     double Bx, double By,
103     double Cx, double Cy,
104     double Px, double Py)
105    
106     {
107     double ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
108     double cCROSSap, bCROSScp, aCROSSbp;
109    
110     ax = Cx - Bx; ay = Cy - By;
111     bx = Ax - Cx; by = Ay - Cy;
112     cx = Bx - Ax; cy = By - Ay;
113     apx= Px - Ax; apy= Py - Ay;
114     bpx= Px - Bx; bpy= Py - By;
115     cpx= Px - Cx; cpy= Py - Cy;
116    
117     aCROSSbp = ax*bpy - ay*bpx;
118     cCROSSap = cx*apy - cy*apx;
119     bCROSScp = bx*cpy - by*cpx;
120    
121     return ((aCROSSbp >= 0.0) && (bCROSScp >= 0.0) && (cCROSSap >= 0.0));
122     };
123    
124     int
125     polyTriangulate(const Vert2_list *contour, tri_out_t *cb)
126     {
127     /* allocate and initialize list of Vertices in polygon */
128    
129 greg 2.4 int nv, m, u, v, w, count, result;
130 greg 2.1 int *V;
131    
132     if ( contour->nv < 3 ) return false;
133    
134     V = (int *)malloc(sizeof(int)*contour->nv);
135     if (V == NULL) return false;
136    
137     /* we want a counter-clockwise polygon in V */
138    
139 greg 2.2 if ( 0.0 < polyArea(contour) )
140 greg 2.1 for (v=0; v<contour->nv; v++) V[v] = v;
141     else
142     for(v=0; v<contour->nv; v++) V[v] = (contour->nv-1)-v;
143    
144     nv = contour->nv;
145    
146     /* remove nv-2 Vertices, creating 1 triangle every time */
147     count = 2*nv; /* error detection */
148    
149     for(m=0, v=nv-1; nv>2; )
150     {
151     /* if we loop, it is probably a non-simple polygon */
152 greg 2.3 if (0 >= count--)
153 greg 2.1 {
154 greg 2.3 /* Triangulate: ERROR - probable bad polygon */
155 greg 2.1 return false;
156     }
157    
158     /* three consecutive vertices in current polygon, <u,v,w> */
159     u = v ; if (nv <= u) u = 0; /* previous */
160     v = u+1; if (nv <= v) v = 0; /* new v */
161     w = v+1; if (nv <= w) w = 0; /* next */
162    
163 greg 2.4 result = polySnip(contour, u, v, w, nv, V);
164     if (result > 0) /* successfully found a triangle */
165 greg 2.1 {
166 greg 2.4 int a,b,c;
167 greg 2.1
168     /* true names of the vertices */
169     a = V[u]; b = V[v]; c = V[w];
170    
171     /* output Triangle */
172 greg 2.2 if (!(*cb)(contour, a, b, c)) return false;
173 greg 2.1
174     m++;
175 greg 2.4 }
176     if (result) /* successfully found a triangle or three consecutive colinear points */
177     {
178     int s,t;
179 greg 2.1
180     /* remove v from remaining polygon */
181     for(s=v,t=v+1;t<nv;s++,t++) V[s] = V[t]; nv--;
182    
183 greg 2.3 /* reset error detection counter */
184 greg 2.1 count = 2*nv;
185     }
186     }
187    
188     free(V);
189    
190     return true;
191     }