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