GRASS 8 Programmer's Manual  8.5.0dev(2025)-c070206eb1
diglib/poly.c
Go to the documentation of this file.
1 /*****************************************************************************
2  *
3  * MODULE: Vector library
4  *
5  * AUTHOR(S): Original author CERL, probably Dave Gerdes.
6  * Update to GRASS 5.7 Radim Blazek.
7  * Update to GRASS 7.0 Markus Metz
8  *
9  * PURPOSE: Lower level functions for reading/writing/manipulating vectors.
10  *
11  * COPYRIGHT: (C) 2009 by the GRASS Development Team
12  *
13  * This program is free software under the GNU General Public
14  * License (>=v2). Read the file COPYING that comes with GRASS
15  * for details.
16  *
17  *****************************************************************************/
18 
19 #include <math.h>
20 #include <grass/vector.h>
21 
22 #ifndef HUGE_VAL
23 #define HUGE_VAL 9999999999999.0
24 #endif
25 
26 /*
27  * fills BPoints (must be inited previously) by points from input
28  * array LPoints
29  *
30  * each input LPoints[i] must have at least 2 points
31  *
32  * returns number of points or -1 on error
33  */
34 int dig_get_poly_points(int n_lines, struct line_pnts **LPoints,
35  int *direction, /* line direction: > 0 or < 0 */
36  struct line_pnts *BPoints)
37 {
38  register int i, j, point, start, end, inc;
39  struct line_pnts *Points;
40  int n_points;
41 
42  BPoints->n_points = 0;
43 
44  if (n_lines < 1) {
45  return 0;
46  }
47 
48  /* Calc required space */
49  n_points = 0;
50  for (i = 0; i < n_lines; i++) {
51  Points = LPoints[i];
52  n_points += Points->n_points - 1; /* each line from first to last - 1 */
53  }
54  n_points++; /* last point */
55 
56  if (0 > dig_alloc_points(BPoints, n_points))
57  return (-1);
58 
59  point = 0;
60  j = 0;
61  for (i = 0; i < n_lines; i++) {
62  Points = LPoints[i];
63  if (direction[i] > 0) {
64  start = 0;
65  end = Points->n_points - 1;
66  inc = 1;
67  }
68  else {
69  start = Points->n_points - 1;
70  end = 0;
71  inc = -1;
72  }
73 
74  for (j = start; j != end; j += inc) {
75  BPoints->x[point] = Points->x[j];
76  BPoints->y[point] = Points->y[j];
77  point++;
78  }
79  }
80  /* last point */
81  BPoints->x[point] = Points->x[j];
82  BPoints->y[point] = Points->y[j];
83 
84  BPoints->n_points = n_points;
85 
86  return (BPoints->n_points);
87 }
88 
89 /*
90  * calculate signed area size for polygon
91  *
92  * points must be closed polygon with first point = last point
93  *
94  * returns signed area, positive for clockwise, negative for
95  * counterclockwise, 0 for degenerate
96  */
97 int dig_find_area_poly(struct line_pnts *Points, double *totalarea)
98 {
99  int i;
100  double *x, *y;
101  double tot_area;
102 
103  x = Points->x;
104  y = Points->y;
105 
106  /* line integral: *Points do not need to be pruned */
107  /* surveyor's formula is more common, but more prone to
108  * fp precision limit errors, and *Points would need to be pruned */
109  tot_area = 0.0;
110  for (i = 1; i < Points->n_points; i++) {
111  tot_area += (x[i] - x[i - 1]) * (y[i] + y[i - 1]);
112  }
113  *totalarea = 0.5 * tot_area;
114 
115  return (0);
116 }
117 
118 /*
119  * find orientation of polygon (clockwise or counterclockwise)
120  * in theory faster than signed area for > 4 vertices, but is not robust
121  * against special cases
122  * use dig_find_area_poly instead
123  *
124  * points must be closed polygon with first point = last point
125  *
126  * this code uses bits and pieces from softSurfer and GEOS
127  * (C) 2000 softSurfer (www.softsurfer.com)
128  * (C) 2006 Refractions Research Inc.
129  *
130  * copes with partially collapsed boundaries and 8-shaped isles
131  * the code is long and not much faster than dig_find_area_poly
132  * it can be written much shorter, but that comes with speed penalty
133  *
134  * returns orientation, positive for CW, negative for CCW, 0 for degenerate
135  */
136 double dig_find_poly_orientation(struct line_pnts *Points)
137 {
138  unsigned int pnext, pprev, pcur = 0;
139  unsigned int lastpoint = Points->n_points - 1;
140  double *x, *y, orientation;
141 
142  x = Points->x;
143  y = Points->y;
144 
145  /* first find leftmost highest vertex of the polygon */
146  for (pnext = 1; pnext < lastpoint; pnext++) {
147  if (y[pnext] < y[pcur])
148  continue;
149  else if (y[pnext] == y[pcur]) { /* just as high */
150  if (x[pnext] > x[pcur]) /* but to the right */
151  continue;
152  if (x[pnext] ==
153  x[pcur]) { /* duplicate point, self-intersecting polygon ? */
154  pprev = (pcur == 0 ? lastpoint - 1 : pcur - 1);
155  if (y[pnext - 1] < y[pprev])
156  continue;
157  }
158  }
159  pcur = pnext; /* a new leftmost highest vertex */
160  }
161 
162  /* Points are not pruned, so ... */
163  pnext = pcur;
164  pprev = pcur;
165 
166  /* find next distinct point */
167  do {
168  if (pnext < lastpoint - 1)
169  pnext++;
170  else
171  pnext = 0;
172  } while (pnext != pcur && x[pcur] == x[pnext] && y[pcur] == y[pnext]);
173 
174  /* find previous distinct point */
175  do {
176  if (pprev > 0)
177  pprev--;
178  else
179  pprev = lastpoint - 1;
180  } while (pprev != pcur && x[pcur] == x[pprev] && y[pcur] == y[pprev]);
181 
182  /* orientation at vertex pcur == signed area for triangle pprev, pcur, pnext
183  * rather use robust determinant of Olivier Devillers? */
184  orientation = (x[pnext] - x[pprev]) * (y[pcur] - y[pprev]) -
185  (x[pcur] - x[pprev]) * (y[pnext] - y[pprev]);
186 
187  if (orientation)
188  return orientation;
189 
190  /* orientation is 0, can happen with dirty boundaries, next check */
191  /* find rightmost highest vertex of the polygon */
192  pcur = 0;
193  for (pnext = 1; pnext < lastpoint; pnext++) {
194  if (y[pnext] < y[pcur])
195  continue;
196  else if (y[pnext] == y[pcur]) { /* just as high */
197  if (x[pnext] < x[pcur]) /* but to the left */
198  continue;
199  if (x[pnext] ==
200  x[pcur]) { /* duplicate point, self-intersecting polygon ? */
201  pprev = (pcur == 0 ? lastpoint - 1 : pcur - 1);
202  if (y[pnext - 1] < y[pprev])
203  continue;
204  }
205  }
206  pcur = pnext; /* a new rightmost highest vertex */
207  }
208 
209  /* Points are not pruned, so ... */
210  pnext = pcur;
211  pprev = pcur;
212 
213  /* find next distinct point */
214  do {
215  if (pnext < lastpoint - 1)
216  pnext++;
217  else
218  pnext = 0;
219  } while (pnext != pcur && x[pcur] == x[pnext] && y[pcur] == y[pnext]);
220 
221  /* find previous distinct point */
222  do {
223  if (pprev > 0)
224  pprev--;
225  else
226  pprev = lastpoint - 1;
227  } while (pprev != pcur && x[pcur] == x[pprev] && y[pcur] == y[pprev]);
228 
229  /* orientation at vertex pcur == signed area for triangle pprev, pcur, pnext
230  * rather use robust determinant of Olivier Devillers? */
231  orientation = (x[pnext] - x[pprev]) * (y[pcur] - y[pprev]) -
232  (x[pcur] - x[pprev]) * (y[pnext] - y[pprev]);
233 
234  if (orientation)
235  return orientation;
236 
237  /* orientation is 0, next check */
238  /* find leftmost lowest vertex of the polygon */
239  pcur = 0;
240  for (pnext = 1; pnext < lastpoint; pnext++) {
241  if (y[pnext] > y[pcur])
242  continue;
243  else if (y[pnext] == y[pcur]) { /* just as low */
244  if (x[pnext] > x[pcur]) /* but to the right */
245  continue;
246  if (x[pnext] ==
247  x[pcur]) { /* duplicate point, self-intersecting polygon ? */
248  pprev = (pcur == 0 ? lastpoint - 1 : pcur - 1);
249  if (y[pnext - 1] > y[pprev])
250  continue;
251  }
252  }
253  pcur = pnext; /* a new leftmost lowest vertex */
254  }
255 
256  /* Points are not pruned, so ... */
257  pnext = pcur;
258  pprev = pcur;
259 
260  /* find next distinct point */
261  do {
262  if (pnext < lastpoint - 1)
263  pnext++;
264  else
265  pnext = 0;
266  } while (pnext != pcur && x[pcur] == x[pnext] && y[pcur] == y[pnext]);
267 
268  /* find previous distinct point */
269  do {
270  if (pprev > 0)
271  pprev--;
272  else
273  pprev = lastpoint - 1;
274  } while (pprev != pcur && x[pcur] == x[pprev] && y[pcur] == y[pprev]);
275 
276  /* orientation at vertex pcur == signed area for triangle pprev, pcur, pnext
277  * rather use robust determinant of Olivier Devillers? */
278  orientation = (x[pnext] - x[pprev]) * (y[pcur] - y[pprev]) -
279  (x[pcur] - x[pprev]) * (y[pnext] - y[pprev]);
280 
281  if (orientation)
282  return orientation;
283 
284  /* orientation is 0, last check */
285  /* find rightmost lowest vertex of the polygon */
286  pcur = 0;
287  for (pnext = 1; pnext < lastpoint; pnext++) {
288  if (y[pnext] > y[pcur])
289  continue;
290  else if (y[pnext] == y[pcur]) { /* just as low */
291  if (x[pnext] < x[pcur]) /* but to the left */
292  continue;
293  if (x[pnext] ==
294  x[pcur]) { /* duplicate point, self-intersecting polygon ? */
295  pprev = (pcur == 0 ? lastpoint - 1 : pcur - 1);
296  if (y[pnext - 1] > y[pprev])
297  continue;
298  }
299  }
300  pcur = pnext; /* a new rightmost lowest vertex */
301  }
302 
303  /* Points are not pruned, so ... */
304  pnext = pcur;
305  pprev = pcur;
306 
307  /* find next distinct point */
308  do {
309  if (pnext < lastpoint - 1)
310  pnext++;
311  else
312  pnext = 0;
313  } while (pnext != pcur && x[pcur] == x[pnext] && y[pcur] == y[pnext]);
314 
315  /* find previous distinct point */
316  do {
317  if (pprev > 0)
318  pprev--;
319  else
320  pprev = lastpoint - 1;
321  } while (pprev != pcur && x[pcur] == x[pprev] && y[pcur] == y[pprev]);
322 
323  /* orientation at vertex pcur == signed area for triangle pprev, pcur, pnext
324  * rather use robust determinant of Olivier Devillers? */
325  orientation = (x[pnext] - x[pprev]) * (y[pcur] - y[pprev]) -
326  (x[pcur] - x[pprev]) * (y[pnext] - y[pprev]);
327 
328  return orientation; /* 0 for degenerate */
329 }
int dig_alloc_points(struct line_pnts *, int)
allocate room for 'num' X and Y arrays in struct line_pnts
Definition: struct_alloc.c:336
int dig_get_poly_points(int n_lines, struct line_pnts **LPoints, int *direction, struct line_pnts *BPoints)
Definition: diglib/poly.c:34
int dig_find_area_poly(struct line_pnts *Points, double *totalarea)
Definition: diglib/poly.c:97
double dig_find_poly_orientation(struct line_pnts *Points)
Definition: diglib/poly.c:136
Feature geometry info - coordinates.
Definition: dig_structs.h:1651
double * y
Array of Y coordinates.
Definition: dig_structs.h:1659
double * x
Array of X coordinates.
Definition: dig_structs.h:1655
int n_points
Number of points.
Definition: dig_structs.h:1667
#define x