GRASS 8 Programmer's Manual 8.6.0dev(2026)-1878fdfec5
Loading...
Searching...
No Matches
vector/Vlib/area.c
Go to the documentation of this file.
1/*!
2 \file lib/vector/Vlib/area.c
3
4 \brief Vector library - area-related functions
5
6 Higher level functions for reading/writing/manipulating vectors.
7
8 SPDX-FileCopyrightText: 2001-2009, 2011-2013 GRASS Development Team
9 SPDX-License-Identifier: GPL-2.0-or-later
10
11 \author Original author CERL, probably Dave Gerdes or Mike Higgins.
12 \author Update to GRASS 5.7 Radim Blazek and David D. Gray.
13 */
14
15#include <stdlib.h>
16#include <grass/vector.h>
17#include <grass/glocale.h>
18
19#ifdef HAVE_POSTGRES
20#include "pg_local_proto.h"
21#endif
22
23#include "local_proto.h"
24
25/*!
26 \brief Returns polygon array of points (outer ring) of given area
27
28 \param Map pointer to Map_info structure
29 \param area area id
30 \param[out] BPoints points array
31
32 \return number of points
33 \return -1 on error
34 */
35int Vect_get_area_points(struct Map_info *Map, int area,
36 struct line_pnts *BPoints)
37{
38 const struct Plus_head *Plus;
39 struct P_area *Area;
40
41 G_debug(3, "Vect_get_area_points(): area = %d", area);
43
44 Plus = &(Map->plus);
45 Area = Plus->Area[area];
46
47 if (Area == NULL) { /* dead area */
48 G_warning(_("Attempt to read points of nonexistent area"));
49 return -1; /* error, because we should not read dead areas */
50 }
51
52 G_debug(3, " n_lines = %d", Area->n_lines);
53 return Vect__get_area_points(Map, Area->lines, Area->n_lines, BPoints);
54}
55
56/*!
57 \brief Returns polygon array of points for given isle
58
59 \param Map pointer to Map_info structure
60 \param isle island id
61 \param[out] BPoints points array
62
63 \return number of points
64 \return -1 on error
65 */
67 struct line_pnts *BPoints)
68{
69 const struct Plus_head *Plus;
70 struct P_isle *Isle;
71
72 G_debug(3, "Vect_get_isle_points(): isle = %d", isle);
74
75 Plus = &(Map->plus);
76 Isle = Plus->Isle[isle];
77
78 if (Isle == NULL) { /* dead isle */
79 G_warning(_("Attempt to read points of nonexistent isle"));
80 return -1; /* error, because we should not read dead isles */
81 }
82
83 G_debug(3, " n_lines = %d", Isle->n_lines);
84
85 if (Map->format == GV_FORMAT_POSTGIS && Map->fInfo.pg.toposchema_name &&
86 Map->fInfo.pg.cache.ctype != CACHE_MAP) {
87#ifdef HAVE_POSTGRES
88 /* PostGIS Topology */
89 return Vect__get_area_points_pg(Map, Isle->lines, Isle->n_lines,
90 BPoints);
91#else
92 G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
93#endif
94 }
95 /* native format */
96 return Vect__get_area_points_nat(Map, Isle->lines, Isle->n_lines, BPoints);
97}
98
99/*!
100 \brief Returns centroid id for given area
101
102 \param Map pointer to Map_info structure
103 \param area area id
104
105 \return centroid id of area
106 \return 0 if no centroid found
107 */
109{
110 const struct Plus_head *Plus;
111 struct P_area *Area;
112
113 G_debug(3, "Vect_get_area_centroid(): area = %d", area);
114
115 Plus = &(Map->plus);
116 Area = Plus->Area[area];
117
118 if (Area == NULL)
119 G_fatal_error(_("Attempt to read topo for dead area (%d)"), area);
120
121 return (Area->centroid);
122}
123
124/*!
125 \brief Creates list of boundaries for given area
126
127 Note that ids in <b>List</b> can be negative. The sign indicates in
128 which direction the boundary should be read (negative for
129 backward).
130
131 \param Map pointer to Map_info structure
132 \param area area id
133 \param[out] List pointer to list of boundaries
134
135 \return number of boundaries
136 */
137int Vect_get_area_boundaries(struct Map_info *Map, int area, struct ilist *List)
138{
139 int i, line;
140 const struct Plus_head *Plus;
141 struct P_area *Area;
142
143 G_debug(3, "Vect_get_area_boundaries(): area = %d", area);
144
146
147 Plus = &(Map->plus);
148 Area = Plus->Area[area];
149
150 if (Area == NULL)
151 G_fatal_error(_("Attempt to read topo for dead area (%d)"), area);
152
153 for (i = 0; i < Area->n_lines; i++) {
154 line = Area->lines[i];
155 Vect_list_append(List, line);
156 }
157
158 return (List->n_values);
159}
160
161/*!
162 \brief Creates list of boundaries for given isle
163
164 Note that ids in <b>List</b> can be negative. The sign indicates in
165 which direction the boundary should be read (negative for forward).
166
167 \param Map pointer to Map_info structure
168 \param isle island number
169 \param[out] List pointer to list where boundaries are stored
170
171 \return number of boundaries
172 */
174{
175 int i, line;
176 const struct Plus_head *Plus;
177 struct P_isle *Isle;
178
179 G_debug(3, "Vect_get_isle_boundaries(): isle = %d", isle);
180
182
183 Plus = &(Map->plus);
184 Isle = Plus->Isle[isle];
185
186 if (Isle == NULL)
187 G_fatal_error(_("Attempt to read topo for dead isle (%d)"), isle);
188
189 for (i = 0; i < Isle->n_lines; i++) {
190 line = Isle->lines[i];
191 Vect_list_append(List, line);
192 }
193
194 return (List->n_values);
195}
196
197/*!
198 \brief Returns number of isles for given area
199
200 \param Map pointer to Map_info structure
201 \param area area id
202
203 \return number of isles for area
204 \return 0 if area not found
205 */
207{
208 const struct Plus_head *Plus;
209 struct P_area *Area;
210
211 G_debug(3, "Vect_get_area_num_isles(): area = %d", area);
212
213 Plus = &(Map->plus);
214 Area = Plus->Area[area];
215
216 if (Area == NULL)
217 G_fatal_error(_("Attempt to read topo for dead area (%d)"), area);
218
219 G_debug(3, " n_isles = %d", Area->n_isles);
220
221 return (Area->n_isles);
222}
223
224/*!
225 \brief Returns isle id for area
226
227 \param Map pointer to Map_info structure
228 \param area area id
229 \param isle isle index (0 .. nisles - 1)
230
231 \return isle id
232 \return 0 if no isle found
233 */
234int Vect_get_area_isle(struct Map_info *Map, int area, int isle)
235{
236 const struct Plus_head *Plus;
237 struct P_area *Area;
238
239 G_debug(3, "Vect_get_area_isle(): area = %d isle = %d", area, isle);
240
241 Plus = &(Map->plus);
242 Area = Plus->Area[area];
243
244 if (Area == NULL)
245 G_fatal_error(_("Attempt to read topo for dead area (%d)"), area);
246
247 G_debug(3, " -> isle = %d", Area->isles[isle]);
248
249 return (Area->isles[isle]);
250}
251
252/*!
253 \brief Returns area id for isle
254
255 \param Map vector
256 \param isle isle number (0 .. nisles - 1)
257
258 \return area id
259 \return 0 area not found
260 */
262{
263 const struct Plus_head *Plus;
264 struct P_isle *Isle;
265
266 G_debug(3, "Vect_get_isle_area(): isle = %d", isle);
267
268 Plus = &(Map->plus);
269 Isle = Plus->Isle[isle];
270
271 if (Isle == NULL)
272 G_fatal_error(_("Attempt to read topo for dead isle (%d)"), isle);
273
274 G_debug(3, " -> area = %d", Isle->area);
275
276 return (Isle->area);
277}
278
279/*!
280 \brief Returns perimeter of area with perimeter of isles
281
282 \param Map pointer to Map_info structure
283 \param area area id
284
285 \return perimeter of area with perimeters of isles in meters
286 */
288{
289 const struct Plus_head *Plus;
290 struct P_area *Area;
291 struct line_pnts *Points;
292 double d;
293 int i;
294
295 G_debug(3, "Vect_get_area_perimeter(): area = %d", area);
296
297 Points = Vect_new_line_struct();
298 Plus = &(Map->plus);
299 Area = Plus->Area[area];
300
301 Vect_get_area_points(Map, area, Points);
302 Vect_line_prune(Points);
303 d = Vect_line_geodesic_length(Points);
304
305 /* adding island perimeters */
306 for (i = 0; i < Area->n_isles; i++) {
307 Vect_get_isle_points(Map, Area->isles[i], Points);
308 Vect_line_prune(Points);
309 d += Vect_line_geodesic_length(Points);
310 }
311
313
314 G_debug(3, " perimeter = %f", d);
315
316 return (d);
317}
318
319/*!
320 \brief Check if point is in area
321
322 \param x,y point coordinates
323 \param Map pointer to Map_info structure
324 \param area area id
325 \param box area bounding box
326
327 \return 0 if point is outside area
328 \return 1 if point is inside area
329 \return 2 if point is on the area's outer ring
330 */
331int Vect_point_in_area(double x, double y, struct Map_info *Map, int area,
332 struct bound_box *box)
333{
334 int i, isle;
335 const struct Plus_head *Plus;
336 struct P_area *Area;
337 struct bound_box ibox;
338 int poly;
339
340 Plus = &(Map->plus);
341 Area = Plus->Area[area];
342 if (Area == NULL)
343 return 0;
344
345 poly = Vect_point_in_area_outer_ring(x, y, Map, area, box);
346 if (poly == 0)
347 return 0;
348
349 if (poly == 2) /* includes area boundary, OK? */
350 return 2;
351
352 /* check if in islands */
353 for (i = 0; i < Area->n_isles; i++) {
354 isle = Area->isles[i];
356 poly = Vect_point_in_island(x, y, Map, isle, &ibox);
357 if (poly >= 1)
358 return 0; /* excludes island boundary (poly == 2), OK? */
359 }
360
361 return 1;
362}
363
364/*!
365 \brief Returns area of area without areas of isles
366
367 \param Map pointer to Map_info structure
368 \param area area id
369
370 \return area of area without areas of isles
371 */
372double Vect_get_area_area(struct Map_info *Map, int area)
373{
374 const struct Plus_head *Plus;
375 struct P_area *Area;
376 struct line_pnts *Points;
377 double size;
378 int i;
379 static int first_time = 1;
380
381 G_debug(3, "Vect_get_area_area(): area = %d", area);
382
383 if (first_time == 1) {
385 first_time = 0;
386 }
387
388 Points = Vect_new_line_struct();
389 Plus = &(Map->plus);
390 Area = Plus->Area[area];
391
392 Vect_get_area_points(Map, area, Points);
393 Vect_line_prune(Points);
394 size = G_area_of_polygon(Points->x, Points->y, Points->n_points);
395
396 /* subtracting island areas */
397 for (i = 0; i < Area->n_isles; i++) {
398 Vect_get_isle_points(Map, Area->isles[i], Points);
399 Vect_line_prune(Points);
400 size -= G_area_of_polygon(Points->x, Points->y, Points->n_points);
401 }
402
404
405 G_debug(3, " area = %f", size);
406
407 return (size);
408}
409
410/*!
411 \brief Get area categories
412
413 \param Map pointer to Map_info structure
414 \param area area id
415 \param[out] Cats list of categories
416
417 \return 0 centroid found (but may be without categories)
418 \return 1 no centroid found
419 */
420int Vect_get_area_cats(struct Map_info *Map, int area, struct line_cats *Cats)
421{
422 int centroid;
423
425
426 centroid = Vect_get_area_centroid(Map, area);
427 if (centroid > 0) {
428 Vect_read_line(Map, NULL, Cats, centroid);
429 }
430 else {
431 return 1; /* no centroid */
432 }
433
434 return 0;
435}
436
437/*!
438 \brief Find FIRST category of given field and area
439
440 \param Map pointer to Map_info structure
441 \param area area id
442 \param field layer number
443
444 \return first found category of given field
445 \return -1 no centroid or no category found
446 */
447int Vect_get_area_cat(struct Map_info *Map, int area, int field)
448{
449 int i;
450 static struct line_cats *Cats = NULL;
451
452 if (!Cats)
454 else
456
457 if (Vect_get_area_cats(Map, area, Cats) == 1 || Cats->n_cats == 0) {
458 return -1;
459 }
460
461 for (i = 0; i < Cats->n_cats; i++) {
462 if (Cats->field[i] == field) {
463 return Cats->cat[i];
464 }
465 }
466
467 return -1;
468}
469
470/*!
471 \brief Get area boundary points (internal use only)
472
473 For PostGIS Topology calls Vect__get_area_points_pg() otherwise
474 Vect__get_area_points_nat(),
475
476 \param Map pointer to Map_info struct
477 \param lines array of boundary lines
478 \param n_lines number of lines in array
479 \param[out] BPoints pointer to output line_pnts struct
480
481 \return number of points
482 \return -1 on error
483 */
484int Vect__get_area_points(struct Map_info *Map, const plus_t *lines,
485 int n_lines, struct line_pnts *BPoints)
486{
487 if (Map->format == GV_FORMAT_POSTGIS && Map->fInfo.pg.toposchema_name &&
488 Map->fInfo.pg.cache.ctype != CACHE_MAP) {
489#ifdef HAVE_POSTGRES
490 /* PostGIS Topology */
491 return Vect__get_area_points_pg(Map, lines, n_lines, BPoints);
492#else
493 G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
494#endif
495 }
496 /* native format */
497 return Vect__get_area_points_nat(Map, lines, n_lines, BPoints);
498}
499
500/*!
501 \brief Get area boundary points (native format)
502
503 Used by Vect_build_line_area() and Vect_get_area_points().
504
505 \param Map pointer to Map_info struct
506 \param lines array of boundary lines
507 \param n_lines number of lines in array
508 \param[out] BPoints pointer to output line_pnts struct
509
510 \return number of points
511 \return -1 on error
512 */
514 int n_lines, struct line_pnts *BPoints)
515{
516 int i, line, aline, dir;
517 static struct line_pnts *Points;
518
519 if (!Points)
520 Points = Vect_new_line_struct();
521
523 for (i = 0; i < n_lines; i++) {
524 line = lines[i];
525 aline = abs(line);
526 G_debug(5, " append line(%d) = %d", i, line);
527
528 if (0 > Vect_read_line(Map, Points, NULL, aline))
529 return -1;
530
531 dir = line > 0 ? GV_FORWARD : GV_BACKWARD;
532 Vect_append_points(BPoints, Points, dir);
533 BPoints->n_points--; /* skip last point, avoids duplicates */
534 }
535 BPoints->n_points++; /* close polygon */
536
537 return BPoints->n_points;
538}
int Vect__get_area_points_pg(struct Map_info *Map, const plus_t *lines, int n_lines, struct line_pnts *APoints)
Get area boundary points (PostGIS Topology)
Definition area_pg.c:35
#define NULL
Definition ccmath.h:32
double G_area_of_polygon(const double *, const double *, int)
Area in square meters of polygon.
Definition gis/area.c:162
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
int G_debug(int, const char *,...) __attribute__((format(printf
int G_begin_polygon_area_calculations(void)
Begin polygon area calculations.
Definition gis/area.c:119
void Vect_destroy_line_struct(struct line_pnts *)
Frees all memory associated with a line_pnts structure, including the structure itself.
Definition line.c:75
int Vect_reset_cats(struct line_cats *)
Reset category structure to make sure cats structure is clean to be re-used.
int Vect_point_in_island(double, double, struct Map_info *, int, struct bound_box *)
Determines if a point (X,Y) is inside an island.
Definition Vlib/poly.c:1045
double Vect_line_geodesic_length(const struct line_pnts *)
Calculate line length.
Definition line.c:600
int Vect_list_append(struct ilist *, int)
Append new item to the end of list if not yet present.
int Vect_read_line(struct Map_info *, struct line_pnts *, struct line_cats *, int)
Read vector feature (topological level required)
int Vect_point_in_area_outer_ring(double, double, struct Map_info *, int, struct bound_box *)
Determines if a point (X,Y) is inside an area outer ring. Islands are not considered.
Definition Vlib/poly.c:1007
struct line_cats * Vect_new_cats_struct(void)
Creates and initializes line_cats structure.
int Vect_get_isle_box(struct Map_info *, int, struct bound_box *)
Get bounding box of isle.
void Vect_reset_line(struct line_pnts *)
Reset line.
Definition line.c:127
int Vect_line_prune(struct line_pnts *)
Remove duplicate points, i.e. zero length segments.
Definition line.c:277
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
Definition line.c:43
int Vect_reset_list(struct ilist *)
Reset ilist structure.
int Vect_append_points(struct line_pnts *, const struct line_pnts *, int)
Appends points to the end of a line.
Definition line.c:333
#define GV_FORMAT_POSTGIS
PostGIS format.
Definition dig_defines.h:89
#define GV_FORWARD
Line direction indicator forward/backward.
#define GV_BACKWARD
int plus_t
plus_t size
Definition dig_structs.h:39
#define _(str)
Definition glocale.h:10
Vector map info.
Area (topology) info.
plus_t n_isles
Number of islands inside.
plus_t * isles
1st generation interior islands
plus_t n_lines
Number of boundary lines.
plus_t * lines
List of boundary lines.
plus_t centroid
Number of first centroid within area.
Isle (topology) info.
plus_t * lines
List of boundary lines.
plus_t n_lines
Number of boundary lines.
plus_t area
Area it exists w/in, if any.
Basic topology-related info.
Bounding box.
Definition dig_structs.h:62
List of integers.
Definition gis.h:712
Feature category info.
int * field
Array of layers (fields)
Feature geometry info - coordinates.
double * y
Array of Y coordinates.
double * x
Array of X coordinates.
int n_points
Number of points.
double Vect_get_area_perimeter(struct Map_info *Map, int area)
Returns perimeter of area with perimeter of isles.
int Vect_get_area_isle(struct Map_info *Map, int area, int isle)
Returns isle id for area.
int Vect_point_in_area(double x, double y, struct Map_info *Map, int area, struct bound_box *box)
Check if point is in area.
int Vect_get_area_points(struct Map_info *Map, int area, struct line_pnts *BPoints)
Returns polygon array of points (outer ring) of given area.
int Vect_get_area_cat(struct Map_info *Map, int area, int field)
Find FIRST category of given field and area.
int Vect_get_area_boundaries(struct Map_info *Map, int area, struct ilist *List)
Creates list of boundaries for given area.
int Vect_get_area_num_isles(struct Map_info *Map, int area)
Returns number of isles for given area.
int Vect__get_area_points(struct Map_info *Map, const plus_t *lines, int n_lines, struct line_pnts *BPoints)
Get area boundary points (internal use only)
int Vect_get_area_centroid(struct Map_info *Map, int area)
Returns centroid id for given area.
int Vect_get_isle_points(struct Map_info *Map, int isle, struct line_pnts *BPoints)
Returns polygon array of points for given isle.
int Vect_get_area_cats(struct Map_info *Map, int area, struct line_cats *Cats)
Get area categories.
int Vect_get_isle_boundaries(struct Map_info *Map, int isle, struct ilist *List)
Creates list of boundaries for given isle.
int Vect__get_area_points_nat(struct Map_info *Map, const plus_t *lines, int n_lines, struct line_pnts *BPoints)
Get area boundary points (native format)
double Vect_get_area_area(struct Map_info *Map, int area)
Returns area of area without areas of isles.
int Vect_get_isle_area(struct Map_info *Map, int isle)
Returns area id for isle.
#define x