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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id$";
3 #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 double Ax, Ay, Bx, By, Cx, Cy, Px, Py, cross;
42
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 cross = ((Bx - Ax)*(Cy - Ay)) - ((By - Ay)*(Cx - Ax));
53 if (EPSILON > cross) return EPSILON > -cross ? -1 : false; /* Negative if colinear points */
54
55 for (p=0;p<n;p++)
56 {
57 if( (p == u) | (p == v) | (p == w) ) continue;
58 Px = contour->v[V[p]].mX;
59 Py = contour->v[V[p]].mY;
60 if ((Px == Ax && Py == Ay) || (Px == Bx && Py == By) ||
61 (Px == Cx && Py == Cy)) continue; /* Handle donuts */
62 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 int nv, m, u, v, w, count, result;
130 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 if ( 0.0 < polyArea(contour) )
140 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 if (0 >= count--)
153 {
154 /* Triangulate: ERROR - probable bad polygon */
155 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 result = polySnip(contour, u, v, w, nv, V);
164 if (result > 0) /* successfully found a triangle */
165 {
166 int a,b,c;
167
168 /* true names of the vertices */
169 a = V[u]; b = V[v]; c = V[w];
170
171 /* output Triangle */
172 if (!(*cb)(contour, a, b, c)) return false;
173
174 m++;
175 }
176 if (result) /* successfully found a triangle or three consecutive colinear points */
177 {
178 int s,t;
179
180 /* remove v from remaining polygon */
181 for(s=v,t=v+1;t<nv;s++,t++) V[s] = V[t]; nv--;
182
183 /* reset error detection counter */
184 count = 2*nv;
185 }
186 }
187
188 free(V);
189
190 return true;
191 }