ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/triangulate.c
Revision: 2.6
Committed: Mon Apr 19 19:40:03 2021 UTC (3 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.5: +24 -23 lines
Log Message:
fix(genbox): Fixed issue with reversed triangles

File Contents

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