GRASS 8 Programmer's Manual 8.6.0dev(2026)-1d1e47ad9d
Loading...
Searching...
No Matches
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 */
34int 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
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 */
97int 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 */
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
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)
Feature geometry info - coordinates.
double * y
Array of Y coordinates.
double * x
Array of X coordinates.
int n_points
Number of points.