QXRD  0.11.16
triangulate.c
Go to the documentation of this file.
1 #include <stdlib.h>
2 
3 #define FALSE 0
4 #define TRUE 1
5 #define EPSILON 1e-10
6 
7 typedef struct {
8  int p1,p2,p3;
9 } ITRIANGLE;
10 typedef struct {
11  int p1,p2;
12 } IEDGE;
13 typedef struct {
14  double x,y,z;
15 } XYZ;
16 
17 /*
18  Triangulation subroutine
19  Takes as input NV vertices in array pxyz
20  Returned is a list of ntri triangular faces in the array v
21  These triangles are arranged in a consistent clockwise order.
22  The triangle array 'v' should be malloced to 3 * nv
23  The vertex array pxyz must be big enough to hold 3 more points
24  The vertex array must be sorted in increasing x values say
25 
26  qsort(p,nv,sizeof(XYZ),XYZCompare);
27  :
28  int XYZCompare(void *v1,void *v2)
29  {
30  XYZ *p1,*p2;
31  p1 = v1;
32  p2 = v2;
33  if (p1->x < p2->x)
34  return(-1);
35  else if (p1->x > p2->x)
36  return(1);
37  else
38  return(0);
39  }
40 */
41 int Triangulate(int nv,XYZ *pxyz,ITRIANGLE *v,int *ntri)
42 {
43  int *complete = NULL;
44  IEDGE *edges = NULL;
45  int nedge = 0;
46  int trimax,emax = 200;
47  int status = 0;
48 
49  int inside;
50  int i,j,k;
51  double xp,yp,x1,y1,x2,y2,x3,y3,xc,yc,r;
52  double xmin,xmax,ymin,ymax,xmid,ymid;
53  double dx,dy,dmax;
54 
55  /* Allocate memory for the completeness list, flag for each triangle */
56  trimax = 4 * nv;
57  if ((complete = malloc(trimax*sizeof(int))) == NULL) {
58  status = 1;
59  goto skip;
60  }
61 
62  /* Allocate memory for the edge list */
63  if ((edges = malloc(emax*(long)sizeof(IEDGE))) == NULL) {
64  status = 2;
65  goto skip;
66  }
67 
68  /*
69  Find the maximum and minimum vertex bounds.
70  This is to allow calculation of the bounding triangle
71  */
72  xmin = pxyz[0].x;
73  ymin = pxyz[0].y;
74  xmax = xmin;
75  ymax = ymin;
76  for (i=1;i<nv;i++) {
77  if (pxyz[i].x < xmin) xmin = pxyz[i].x;
78  if (pxyz[i].x > xmax) xmax = pxyz[i].x;
79  if (pxyz[i].y < ymin) ymin = pxyz[i].y;
80  if (pxyz[i].y > ymax) ymax = pxyz[i].y;
81  }
82  dx = xmax - xmin;
83  dy = ymax - ymin;
84  dmax = (dx > dy) ? dx : dy;
85  xmid = (xmax + xmin) / 2.0;
86  ymid = (ymax + ymin) / 2.0;
87 
88  /*
89  Set up the supertriangle
90  This is a triangle which encompasses all the sample points.
91  The supertriangle coordinates are added to the end of the
92  vertex list. The supertriangle is the first triangle in
93  the triangle list.
94  */
95  pxyz[nv+0].x = xmid - 20 * dmax;
96  pxyz[nv+0].y = ymid - dmax;
97  pxyz[nv+0].z = 0.0;
98  pxyz[nv+1].x = xmid;
99  pxyz[nv+1].y = ymid + 20 * dmax;
100  pxyz[nv+1].z = 0.0;
101  pxyz[nv+2].x = xmid + 20 * dmax;
102  pxyz[nv+2].y = ymid - dmax;
103  pxyz[nv+2].z = 0.0;
104  v[0].p1 = nv;
105  v[0].p2 = nv+1;
106  v[0].p3 = nv+2;
107  complete[0] = FALSE;
108  *ntri = 1;
109 
110  /*
111  Include each point one at a time into the existing mesh
112  */
113  for (i=0;i<nv;i++) {
114 
115  xp = pxyz[i].x;
116  yp = pxyz[i].y;
117  nedge = 0;
118 
119  /*
120  Set up the edge buffer.
121  If the point (xp,yp) lies inside the circumcircle then the
122  three edges of that triangle are added to the edge buffer
123  and that triangle is removed.
124  */
125  for (j=0;j<(*ntri);j++) {
126  if (complete[j])
127  continue;
128  x1 = pxyz[v[j].p1].x;
129  y1 = pxyz[v[j].p1].y;
130  x2 = pxyz[v[j].p2].x;
131  y2 = pxyz[v[j].p2].y;
132  x3 = pxyz[v[j].p3].x;
133  y3 = pxyz[v[j].p3].y;
134  inside = CircumCircle(xp,yp,x1,y1,x2,y2,x3,y3,&xc,&yc,&r);
135  if (xc < xp && ((xp-xc)*(xp-xc)) > r)
136  complete[j] = TRUE;
137  if (inside) {
138  /* Check that we haven't exceeded the edge list size */
139  if (nedge+3 >= emax) {
140  emax += 100;
141  if ((edges = realloc(edges,emax*(long)sizeof(IEDGE))) == NULL) {
142  status = 3;
143  goto skip;
144  }
145  }
146  edges[nedge+0].p1 = v[j].p1;
147  edges[nedge+0].p2 = v[j].p2;
148  edges[nedge+1].p1 = v[j].p2;
149  edges[nedge+1].p2 = v[j].p3;
150  edges[nedge+2].p1 = v[j].p3;
151  edges[nedge+2].p2 = v[j].p1;
152  nedge += 3;
153  v[j] = v[(*ntri)-1];
154  complete[j] = complete[(*ntri)-1];
155  (*ntri)--;
156  j--;
157  }
158  }
159 
160  /*
161  Tag multiple edges
162  Note: if all triangles are specified anticlockwise then all
163  interior edges are opposite pointing in direction.
164  */
165  for (j=0;j<nedge-1;j++) {
166  for (k=j+1;k<nedge;k++) {
167  if ((edges[j].p1 == edges[k].p2) && (edges[j].p2 == edges[k].p1)) {
168  edges[j].p1 = -1;
169  edges[j].p2 = -1;
170  edges[k].p1 = -1;
171  edges[k].p2 = -1;
172  }
173  /* Shouldn't need the following, see note above */
174  if ((edges[j].p1 == edges[k].p1) && (edges[j].p2 == edges[k].p2)) {
175  edges[j].p1 = -1;
176  edges[j].p2 = -1;
177  edges[k].p1 = -1;
178  edges[k].p2 = -1;
179  }
180  }
181  }
182 
183  /*
184  Form new triangles for the current point
185  Skipping over any tagged edges.
186  All edges are arranged in clockwise order.
187  */
188  for (j=0;j<nedge;j++) {
189  if (edges[j].p1 < 0 || edges[j].p2 < 0)
190  continue;
191  if ((*ntri) >= trimax) {
192  status = 4;
193  goto skip;
194  }
195  v[*ntri].p1 = edges[j].p1;
196  v[*ntri].p2 = edges[j].p2;
197  v[*ntri].p3 = i;
198  complete[*ntri] = FALSE;
199  (*ntri)++;
200  }
201  }
202 
203  /*
204  Remove triangles with supertriangle vertices
205  These are triangles which have a vertex number greater than nv
206  */
207  for (i=0;i<(*ntri);i++) {
208  if (v[i].p1 >= nv || v[i].p2 >= nv || v[i].p3 >= nv) {
209  v[i] = v[(*ntri)-1];
210  (*ntri)--;
211  i--;
212  }
213  }
214 
215 skip:
216  free(edges);
217  free(complete);
218  return(status);
219 }
220 
221 /*
222  Return TRUE if a point (xp,yp) is inside the circumcircle made up
223  of the points (x1,y1), (x2,y2), (x3,y3)
224  The circumcircle centre is returned in (xc,yc) and the radius r
225  NOTE: A point on the edge is inside the circumcircle
226 */
227 int CircumCircle(double xp,double yp,
228  double x1,double y1,double x2,double y2,double x3,double y3,
229  double *xc,double *yc,double *rsqr)
230 {
231  double m1,m2,mx1,mx2,my1,my2;
232  double dx,dy,drsqr;
233  double fabsy1y2 = fabs(y1-y2);
234  double fabsy2y3 = fabs(y2-y3);
235 
236  /* Check for coincident points */
237  if (fabsy1y2 < EPSILON && fabsy2y3 < EPSILON)
238  return(FALSE);
239 
240  if (fabsy1y2 < EPSILON) {
241  m2 = - (x3-x2) / (y3-y2);
242  mx2 = (x2 + x3) / 2.0;
243  my2 = (y2 + y3) / 2.0;
244  *xc = (x2 + x1) / 2.0;
245  *yc = m2 * (*xc - mx2) + my2;
246  } else if (fabsy2y3 < EPSILON) {
247  m1 = - (x2-x1) / (y2-y1);
248  mx1 = (x1 + x2) / 2.0;
249  my1 = (y1 + y2) / 2.0;
250  *xc = (x3 + x2) / 2.0;
251  *yc = m1 * (*xc - mx1) + my1;
252  } else {
253  m1 = - (x2-x1) / (y2-y1);
254  m2 = - (x3-x2) / (y3-y2);
255  mx1 = (x1 + x2) / 2.0;
256  mx2 = (x2 + x3) / 2.0;
257  my1 = (y1 + y2) / 2.0;
258  my2 = (y2 + y3) / 2.0;
259  *xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
260  if (fabsy1y2 > fabsy2y3) {
261  *yc = m1 * (*xc - mx1) + my1;
262  } else {
263  *yc = m2 * (*xc - mx2) + my2;
264  }
265  }
266 
267  dx = x2 - *xc;
268  dy = y2 - *yc;
269  *rsqr = dx*dx + dy*dy;
270 
271  dx = xp - *xc;
272  dy = yp - *yc;
273  drsqr = dx*dx + dy*dy;
274 
275  // Original
276  //return((drsqr <= *rsqr) ? TRUE : FALSE);
277  // Proposed by Chuck Morris
278  return((drsqr - *rsqr) <= EPSILON ? TRUE : FALSE);
279 }
280 
int p2
Definition: triangulate.c:11
#define FALSE
Definition: triangulate.c:3
int Triangulate(int nv, XYZ *pxyz, ITRIANGLE *v, int *ntri)
Definition: triangulate.c:41
int CircumCircle(double xp, double yp, double x1, double y1, double x2, double y2, double x3, double y3, double *xc, double *yc, double *rsqr)
Definition: triangulate.c:227
double x
Definition: triangulate.c:14
#define TRUE
Definition: triangulate.c:4
double z
Definition: triangulate.c:14
#define EPSILON
Definition: triangulate.c:5
double y
Definition: triangulate.c:14
int p1
Definition: triangulate.c:11