GRASS 8 Programmer's Manual 8.6.0dev(2026)-f808a6d29a
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, mid;
100 double *x, *y, xshift, yshift;
101 double tot_area;
102
103 x = Points->x;
104 y = Points->y;
105
106 /* Get a reference point close to the polygon as new origin.
107 * The first point would be good enough, particularly for small
108 * polygons. The average of the first and the mid-point is a fast
109 * approximation of a reference point with reduced distance to the
110 * ring's vertices, also for larger rings.
111 *
112 * Shift coordinates towards this reference point to make
113 * calculation of the signed area more robust by increasing the
114 * accuracy for given fp precision limits.
115 *
116 * Considering the basic formula
117 * area += (x2 - x1) * (y2 + y1)
118 * the shift is in theory only needed for addition, not subtraction,
119 * but does no harm and is kept for symmetry treating x and y coords.
120 *
121 * Keep in sync with G_planimetric_polygon_area() in lib/gis/area_poly2.c */
122
123 mid = Points->n_points / 2;
124 xshift = (x[0] + x[mid]) / 2.;
125 yshift = (y[0] + y[mid]) / 2.;
126
127 /* line integral: *Points do not need to be pruned */
128 /* surveyor's formula is more common, but more prone to
129 * fp precision limit errors, and *Points would need to be pruned */
130 tot_area = 0.0;
131 for (i = 1; i < Points->n_points; i++) {
132 tot_area += ((x[i] - xshift) - (x[i - 1] - xshift)) *
133 ((y[i] - yshift) + (y[i - 1] - yshift));
134 }
135 *totalarea = 0.5 * tot_area;
136
137 return (0);
138}
139
140/*
141 * find orientation of polygon (clockwise or counterclockwise)
142 * in theory faster than signed area for > 4 vertices, but is not robust
143 * against special cases
144 * use dig_find_area_poly instead
145 *
146 * points must be closed polygon with first point = last point
147 *
148 * this code uses bits and pieces from softSurfer and GEOS
149 * (C) 2000 softSurfer (www.softsurfer.com)
150 * (C) 2006 Refractions Research Inc.
151 *
152 * copes with partially collapsed boundaries and 8-shaped isles
153 * the code is long and not much faster than dig_find_area_poly
154 * it can be written much shorter, but that comes with speed penalty
155 *
156 * returns orientation, positive for CW, negative for CCW, 0 for degenerate
157 */
159{
160 unsigned int pnext, pprev, pcur = 0;
161 unsigned int lastpoint = Points->n_points - 1;
162 double *x, *y, orientation;
163
164 x = Points->x;
165 y = Points->y;
166
167 /* first find leftmost highest vertex of the polygon */
168 for (pnext = 1; pnext < lastpoint; pnext++) {
169 if (y[pnext] < y[pcur])
170 continue;
171 else if (y[pnext] == y[pcur]) { /* just as high */
172 if (x[pnext] > x[pcur]) /* but to the right */
173 continue;
174 if (x[pnext] ==
175 x[pcur]) { /* duplicate point, self-intersecting polygon ? */
176 pprev = (pcur == 0 ? lastpoint - 1 : pcur - 1);
177 if (y[pnext - 1] < y[pprev])
178 continue;
179 }
180 }
181 pcur = pnext; /* a new leftmost highest vertex */
182 }
183
184 /* Points are not pruned, so ... */
185 pnext = pcur;
186 pprev = pcur;
187
188 /* find next distinct point */
189 do {
190 if (pnext < lastpoint - 1)
191 pnext++;
192 else
193 pnext = 0;
194 } while (pnext != pcur && x[pcur] == x[pnext] && y[pcur] == y[pnext]);
195
196 /* find previous distinct point */
197 do {
198 if (pprev > 0)
199 pprev--;
200 else
201 pprev = lastpoint - 1;
202 } while (pprev != pcur && x[pcur] == x[pprev] && y[pcur] == y[pprev]);
203
204 /* orientation at vertex pcur == signed area for triangle pprev, pcur, pnext
205 * rather use robust determinant of Olivier Devillers? */
206 orientation = (x[pnext] - x[pprev]) * (y[pcur] - y[pprev]) -
207 (x[pcur] - x[pprev]) * (y[pnext] - y[pprev]);
208
209 if (orientation)
210 return orientation;
211
212 /* orientation is 0, can happen with dirty boundaries, next check */
213 /* find rightmost highest vertex of the polygon */
214 pcur = 0;
215 for (pnext = 1; pnext < lastpoint; pnext++) {
216 if (y[pnext] < y[pcur])
217 continue;
218 else if (y[pnext] == y[pcur]) { /* just as high */
219 if (x[pnext] < x[pcur]) /* but to the left */
220 continue;
221 if (x[pnext] ==
222 x[pcur]) { /* duplicate point, self-intersecting polygon ? */
223 pprev = (pcur == 0 ? lastpoint - 1 : pcur - 1);
224 if (y[pnext - 1] < y[pprev])
225 continue;
226 }
227 }
228 pcur = pnext; /* a new rightmost highest vertex */
229 }
230
231 /* Points are not pruned, so ... */
232 pnext = pcur;
233 pprev = pcur;
234
235 /* find next distinct point */
236 do {
237 if (pnext < lastpoint - 1)
238 pnext++;
239 else
240 pnext = 0;
241 } while (pnext != pcur && x[pcur] == x[pnext] && y[pcur] == y[pnext]);
242
243 /* find previous distinct point */
244 do {
245 if (pprev > 0)
246 pprev--;
247 else
248 pprev = lastpoint - 1;
249 } while (pprev != pcur && x[pcur] == x[pprev] && y[pcur] == y[pprev]);
250
251 /* orientation at vertex pcur == signed area for triangle pprev, pcur, pnext
252 * rather use robust determinant of Olivier Devillers? */
253 orientation = (x[pnext] - x[pprev]) * (y[pcur] - y[pprev]) -
254 (x[pcur] - x[pprev]) * (y[pnext] - y[pprev]);
255
256 if (orientation)
257 return orientation;
258
259 /* orientation is 0, next check */
260 /* find leftmost lowest vertex of the polygon */
261 pcur = 0;
262 for (pnext = 1; pnext < lastpoint; pnext++) {
263 if (y[pnext] > y[pcur])
264 continue;
265 else if (y[pnext] == y[pcur]) { /* just as low */
266 if (x[pnext] > x[pcur]) /* but to the right */
267 continue;
268 if (x[pnext] ==
269 x[pcur]) { /* duplicate point, self-intersecting polygon ? */
270 pprev = (pcur == 0 ? lastpoint - 1 : pcur - 1);
271 if (y[pnext - 1] > y[pprev])
272 continue;
273 }
274 }
275 pcur = pnext; /* a new leftmost lowest vertex */
276 }
277
278 /* Points are not pruned, so ... */
279 pnext = pcur;
280 pprev = pcur;
281
282 /* find next distinct point */
283 do {
284 if (pnext < lastpoint - 1)
285 pnext++;
286 else
287 pnext = 0;
288 } while (pnext != pcur && x[pcur] == x[pnext] && y[pcur] == y[pnext]);
289
290 /* find previous distinct point */
291 do {
292 if (pprev > 0)
293 pprev--;
294 else
295 pprev = lastpoint - 1;
296 } while (pprev != pcur && x[pcur] == x[pprev] && y[pcur] == y[pprev]);
297
298 /* orientation at vertex pcur == signed area for triangle pprev, pcur, pnext
299 * rather use robust determinant of Olivier Devillers? */
300 orientation = (x[pnext] - x[pprev]) * (y[pcur] - y[pprev]) -
301 (x[pcur] - x[pprev]) * (y[pnext] - y[pprev]);
302
303 if (orientation)
304 return orientation;
305
306 /* orientation is 0, last check */
307 /* find rightmost lowest vertex of the polygon */
308 pcur = 0;
309 for (pnext = 1; pnext < lastpoint; pnext++) {
310 if (y[pnext] > y[pcur])
311 continue;
312 else if (y[pnext] == y[pcur]) { /* just as low */
313 if (x[pnext] < x[pcur]) /* but to the left */
314 continue;
315 if (x[pnext] ==
316 x[pcur]) { /* duplicate point, self-intersecting polygon ? */
317 pprev = (pcur == 0 ? lastpoint - 1 : pcur - 1);
318 if (y[pnext - 1] > y[pprev])
319 continue;
320 }
321 }
322 pcur = pnext; /* a new rightmost lowest vertex */
323 }
324
325 /* Points are not pruned, so ... */
326 pnext = pcur;
327 pprev = pcur;
328
329 /* find next distinct point */
330 do {
331 if (pnext < lastpoint - 1)
332 pnext++;
333 else
334 pnext = 0;
335 } while (pnext != pcur && x[pcur] == x[pnext] && y[pcur] == y[pnext]);
336
337 /* find previous distinct point */
338 do {
339 if (pprev > 0)
340 pprev--;
341 else
342 pprev = lastpoint - 1;
343 } while (pprev != pcur && x[pcur] == x[pprev] && y[pcur] == y[pprev]);
344
345 /* orientation at vertex pcur == signed area for triangle pprev, pcur, pnext
346 * rather use robust determinant of Olivier Devillers? */
347 orientation = (x[pnext] - x[pprev]) * (y[pcur] - y[pprev]) -
348 (x[pcur] - x[pprev]) * (y[pnext] - y[pprev]);
349
350 return orientation; /* 0 for degenerate */
351}
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.