GRASS 8 Programmer's Manual 8.6.0dev(2026)-5f4f7ad06c
Loading...
Searching...
No Matches
remove_areas.c
Go to the documentation of this file.
1/*!
2 \file lib/vector/Vlib/remove_areas.c
3
4 \brief Vector library - clean geometry (remove small areas)
5
6 Higher level functions for reading/writing/manipulating vectors.
7
8 (C) 2001-2009 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 Radim Blazek, Markus Metz
14 */
15
16#include <stdlib.h>
17#include <grass/vector.h>
18#include <grass/glocale.h>
19
20int Vect_remove_small_areas_nat(struct Map_info *, double, struct Map_info *,
21 double *);
22
23int Vect_remove_small_areas_ext(struct Map_info *, double, struct Map_info *,
24 double *);
25
26/*!
27 \brief Remove small areas from the map map.
28
29 Centroid of the area and the longest boundary with adjacent area is
30 removed. Map topology must be built GV_BUILD_CENTROIDS.
31
32 \param[in,out] Map vector map
33 \param thresh maximum area size for removed areas
34 \param[out] Err vector map where removed lines and centroids are written
35 \param removed_area pointer to where total size of removed area is stored or
36 NULL
37
38 \return number of removed areas
39 */
41 struct Map_info *Err, double *removed_area)
42{
43
44 if (Map->format == GV_FORMAT_NATIVE)
46 else
48}
49
51 struct Map_info *Err, double *removed_area)
52{
53 int area, nareas;
54 int nremoved = 0;
55 struct ilist *List;
56 struct ilist *AList;
57 struct line_pnts *Points;
58 struct line_cats *Cats;
59 double size_removed = 0.0;
60
63 Points = Vect_new_line_struct();
65
67 for (area = 1; area <= nareas; area++) {
68 int i, j, centroid, dissolve_neighbour;
69 double length, size;
70
71 G_percent(area, nareas, 1);
72 G_debug(3, "area = %d", area);
73 if (!Vect_area_alive(Map, area))
74 continue;
75
76 size = Vect_get_area_area(Map, area);
77 if (size > thresh)
78 continue;
79 size_removed += size;
80
81 /* The area is smaller than the limit -> remove */
82
83 /* Remove centroid */
84 centroid = Vect_get_area_centroid(Map, area);
85 if (centroid > 0) {
86 if (Err) {
87 Vect_read_line(Map, Points, Cats, centroid);
89 }
90 Vect_delete_line(Map, centroid);
91 }
92
93 /* Find the adjacent area with which the longest boundary is shared */
94
96
97 /* Create a list of neighbour areas */
99 for (i = 0; i < List->n_values; i++) {
100 int line, left, right, neighbour;
101
102 line = List->value[i];
103
104 if (!Vect_line_alive(Map, abs(line))) /* Should not happen */
105 G_fatal_error(_("Area is composed of dead boundary"));
106
107 Vect_get_line_areas(Map, abs(line), &left, &right);
108 if (line > 0)
109 neighbour = left;
110 else
111 neighbour = right;
112
113 G_debug(4, " line = %d left = %d right = %d neighbour = %d", line,
114 left, right, neighbour);
115
116 Vect_list_append(AList, neighbour); /* this checks for duplicity */
117 }
118 G_debug(3, "num neighbours = %d", AList->n_values);
119
120 /* Go through the list of neighbours and find that with the longest
121 * boundary */
123 length = -1.0;
124 for (i = 0; i < AList->n_values; i++) {
125 int neighbour1;
126 double l = 0.0;
127
128 neighbour1 = AList->value[i];
129 G_debug(4, " neighbour1 = %d", neighbour1);
130
131 for (j = 0; j < List->n_values; j++) {
132 int line, left, right, neighbour2;
133
134 line = List->value[j];
135 Vect_get_line_areas(Map, abs(line), &left, &right);
136 if (line > 0)
137 neighbour2 = left;
138 else
139 neighbour2 = right;
140
141 if (neighbour2 == neighbour1) {
142 Vect_read_line(Map, Points, NULL, abs(line));
143 l += Vect_line_length(Points);
144 }
145 }
146 if (l > length) {
147 length = l;
149 }
150 }
151
152 G_debug(3, "dissolve_neighbour = %d", dissolve_neighbour);
153
154 /* Make list of boundaries to be removed */
156 for (i = 0; i < List->n_values; i++) {
157 int line, left, right, neighbour;
158
159 line = List->value[i];
160 Vect_get_line_areas(Map, abs(line), &left, &right);
161 if (line > 0)
162 neighbour = left;
163 else
164 neighbour = right;
165
166 G_debug(3, " neighbour = %d", neighbour);
167
169 Vect_list_append(AList, abs(line));
170 }
171 }
172
173 /* Remove boundaries */
174 for (i = 0; i < AList->n_values; i++) {
175 int line;
176
177 line = AList->value[i];
178
179 if (Err) {
180 Vect_read_line(Map, Points, Cats, line);
182 }
183 Vect_delete_line(Map, line);
184 }
185
186 nremoved++;
188 }
189
190 if (removed_area)
192
193 G_message(_("%d areas of total size %g removed"), nremoved, size_removed);
198
199 return (nremoved);
200}
201
202/* much faster version */
204 struct Map_info *Err, double *removed_area)
205{
206 int area, nareas;
207 int nremoved = 0;
208 struct ilist *List;
209 struct ilist *AList;
210 struct ilist *BList;
211 struct ilist *NList;
212 struct ilist *IList;
213 struct line_pnts *Points;
214 struct line_cats *Cats;
215 double size_removed = 0.0;
217 int line, left, right, neighbour;
218 int nisles, nnisles;
219
225 Points = Vect_new_line_struct();
227
229 for (area = 1; area <= nareas; area++) {
230 int i, j, centroid, ncentroid;
231 double length, l, size;
232 int outer_area = -1;
233 int narea, same_atype = 0;
234
235 G_percent(area, nareas, 1);
236 G_debug(3, "area = %d", area);
237 if (!Vect_area_alive(Map, area))
238 continue;
239
240 size = Vect_get_area_area(Map, area);
241 if (size > thresh)
242 continue;
243 size_removed += size;
244
245 /* The area is smaller than the limit -> remove */
246
247 /* Remove centroid */
248 centroid = Vect_get_area_centroid(Map, area);
249 if (centroid > 0) {
250 if (Err) {
251 Vect_read_line(Map, Points, Cats, centroid);
253 }
254 Vect_delete_line(Map, centroid);
255 }
256
257 /* Find the adjacent area with which the longest boundary is shared */
258
260
261 /* Create a list of neighbour areas */
263 for (i = 0; i < List->n_values; i++) {
264
265 line = List->value[i];
266
267 if (!Vect_line_alive(Map, abs(line))) /* Should not happen */
268 G_fatal_error(_("Area is composed of dead boundary"));
269
270 Vect_get_line_areas(Map, abs(line), &left, &right);
271 if (line > 0)
272 neighbour = left;
273 else
274 neighbour = right;
275
276 G_debug(4, " line = %d left = %d right = %d neighbour = %d", line,
277 left, right, neighbour);
278
279 ncentroid = 0;
280 if (neighbour > 0) {
282 }
283 if (neighbour < 0) {
285 if (narea > 0)
287 }
288 if ((centroid != 0) + (ncentroid != 0) != 1)
289 same_atype = 1;
290
291 Vect_list_append(AList, neighbour); /* this checks for duplicity */
292 }
293 G_debug(3, "num neighbours = %d", AList->n_values);
294
295 if (AList->n_values == 1)
296 same_atype = 0;
297
298 /* Go through the list of neighbours and find the one with the longest
299 * boundary */
301 length = -1.0;
302 for (i = 0; i < AList->n_values; i++) {
303 int neighbour1;
304
305 l = 0.0;
306 neighbour1 = AList->value[i];
307 G_debug(4, " neighbour1 = %d", neighbour1);
308
309 if (same_atype) {
310 ncentroid = 0;
311 if (neighbour1 > 0) {
313 }
314 if (neighbour1 < 0) {
316 if (narea > 0)
318 }
319 if ((centroid != 0) + (ncentroid != 0) == 1)
320 continue;
321 }
322
323 for (j = 0; j < List->n_values; j++) {
324 int neighbour2;
325
326 line = List->value[j];
327 Vect_get_line_areas(Map, abs(line), &left, &right);
328 if (line > 0)
329 neighbour2 = left;
330 else
331 neighbour2 = right;
332
333 if (neighbour2 == neighbour1) {
334 Vect_read_line(Map, Points, NULL, abs(line));
335 l += Vect_line_length(Points);
336 }
337 }
338 if (l > length) {
339 length = l;
341 }
342 }
343
344 G_debug(3, "dissolve_neighbour = %d", dissolve_neighbour);
345
346 if (dissolve_neighbour == 0) {
347 G_fatal_error("could not find neighbour to dissolve");
348 }
349
350 /* Make list of boundaries to be removed */
353 for (i = 0; i < List->n_values; i++) {
354
355 line = List->value[i];
356 Vect_get_line_areas(Map, abs(line), &left, &right);
357 if (line > 0)
358 neighbour = left;
359 else
360 neighbour = right;
361
362 G_debug(3, " neighbour = %d", neighbour);
363
365 Vect_list_append(AList, abs(line));
366 }
367 else
368 Vect_list_append(BList, line);
369 }
370 G_debug(3, "remove %d of %d boundaries", AList->n_values,
371 List->n_values);
372
373 /* Get isles inside area */
375 if ((nisles = Vect_get_area_num_isles(Map, area)) > 0) {
376 for (i = 0; i < nisles; i++) {
378 }
379 }
380
381 /* Remove boundaries */
382 for (i = 0; i < AList->n_values; i++) {
383 int ret;
384
385 line = AList->value[i];
386
387 if (Err) {
388 Vect_read_line(Map, Points, Cats, line);
390 }
391 /* Vect_delete_line(Map, line); */
392
393 /* delete the line from coor */
394 ret = V1_delete_line_nat(Map, Map->plus.Line[line]->offset);
395
396 if (ret == -1) {
397 G_fatal_error(_("Could not delete line from coor"));
398 }
399 }
400
401 /* update topo */
402 if (dissolve_neighbour > 0) {
403
404 G_debug(3, "dissolve with neighbour area");
405
406 /* get neighbour centroid */
408 /* get neighbour isles */
410 0) {
411 for (i = 0; i < nnisles; i++) {
414 }
415 }
416
417 /* get neighbour boundaries */
419
420 /* delete area from topo */
421 dig_del_area(&(Map->plus), area);
422 /* delete neighbour area from topo */
424 /* delete boundaries from topo */
425 for (i = 0; i < AList->n_values; i++) {
426 struct P_topo_b *topo;
427 struct P_node *Node;
428
429 line = AList->value[i];
430 topo = (struct P_topo_b *)Map->plus.Line[line]->topo;
431 Node = Map->plus.Node[topo->N1];
432 dig_del_line(&(Map->plus), line, Node->x, Node->y, Node->z);
433 }
434 /* build new area from leftover boundaries of deleted area */
435 for (i = 0; i < BList->n_values; i++) {
436 struct P_topo_b *topo;
437 int new_isle;
438
439 line = BList->value[i];
440 topo = Map->plus.Line[abs(line)]->topo;
441
442 if (topo->left == 0 || topo->right == 0) {
444 Map, abs(line), (line > 0 ? GV_RIGHT : GV_LEFT));
445 if (new_isle > 0) {
446 if (outer_area > 0)
447 G_fatal_error("dissolve_neighbour > 0, new area "
448 "has already been created");
450 /* reattach centroid */
451 Map->plus.Area[outer_area]->centroid = centroid;
452 if (centroid > 0) {
453 struct P_topo_c *ctopo =
454 Map->plus.Line[centroid]->topo;
455
456 ctopo->area = outer_area;
457 }
458 }
459 else if (new_isle < 0) {
460 /* leftover boundary creates a new isle */
462 }
463 else {
464 /* neither area nor isle, should not happen */
465 G_fatal_error(_("dissolve_neighbour > 0, failed to "
466 "build new area"));
467 }
468 }
469 /* check */
470 if (topo->left == 0 || topo->right == 0)
472 _("Dissolve with neighbour area: corrupt topology"));
473 }
474 /* build new area from neighbour's boundaries */
475 for (i = 0; i < NList->n_values; i++) {
476 struct P_topo_b *topo;
477
478 line = NList->value[i];
479 if (!Vect_line_alive(Map, abs(line)))
480 continue;
481
482 topo = Map->plus.Line[abs(line)]->topo;
483
484 if (topo->left == 0 || topo->right == 0) {
485 int new_isle;
486
488 Map, abs(line), (line > 0 ? GV_RIGHT : GV_LEFT));
489 if (new_isle > 0) {
490 if (outer_area > 0)
491 G_fatal_error("dissolve_neighbour > 0, new area "
492 "has already been created");
494 /* reattach centroid */
495 Map->plus.Area[outer_area]->centroid = centroid;
496 if (centroid > 0) {
497 struct P_topo_c *ctopo =
498 Map->plus.Line[centroid]->topo;
499
500 ctopo->area = outer_area;
501 }
502 }
503 else if (new_isle < 0) {
504 /* Neigbour's boundary creates a new isle */
506 }
507 else {
508 /* neither area nor isle, should not happen */
509 G_fatal_error(_("Failed to build new area"));
510 }
511 }
512 if (topo->left == 0 || topo->right == 0)
514 _("Dissolve with neighbour area: corrupt topology"));
515 }
516 }
517 /* dissolve with outer isle */
518 else if (dissolve_neighbour < 0) {
519
520 G_debug(3, "dissolve with outer isle");
521
523
524 /* get isle boundaries */
526
527 /* delete area from topo */
528 dig_del_area(&(Map->plus), area);
529 /* delete isle from topo */
531 /* delete boundaries from topo */
532 for (i = 0; i < AList->n_values; i++) {
533 struct P_topo_b *topo;
534 struct P_node *Node;
535
536 line = AList->value[i];
537 topo = (struct P_topo_b *)Map->plus.Line[line]->topo;
538 Node = Map->plus.Node[topo->N1];
539 dig_del_line(&(Map->plus), line, Node->x, Node->y, Node->z);
540 }
541 /* build new isle(s) from leftover boundaries */
542 for (i = 0; i < BList->n_values; i++) {
543 struct P_topo_b *topo;
544
545 line = BList->value[i];
546 topo = Map->plus.Line[abs(line)]->topo;
547
548 if (topo->left == 0 || topo->right == 0) {
549 int new_isle;
550
552 Map, abs(line), (line > 0 ? GV_RIGHT : GV_LEFT));
553 if (new_isle < 0) {
555 }
556 else {
557 /* area or nothing should not happen */
558 G_fatal_error(_("Failed to build new isle"));
559 }
560 }
561 /* check */
562 if (topo->left == 0 || topo->right == 0)
564 _("Dissolve with outer isle: corrupt topology"));
565 }
566
567 /* build new isle(s) from old isle's boundaries */
568 for (i = 0; i < NList->n_values; i++) {
569 struct P_topo_b *topo;
570
571 line = NList->value[i];
572 if (!Vect_line_alive(Map, abs(line)))
573 continue;
574
575 topo = Map->plus.Line[abs(line)]->topo;
576
577 if (topo->left == 0 || topo->right == 0) {
578 int new_isle;
579
581 Map, abs(line), (line > 0 ? GV_RIGHT : GV_LEFT));
582 if (new_isle < 0) {
584 }
585 else {
586 /* area or nothing should not happen */
587 G_fatal_error(_("Failed to build new isle"));
588 }
589 }
590 /* check */
591 if (topo->left == 0 || topo->right == 0)
593 _("Dissolve with outer isle: corrupt topology"));
594 }
595 }
596
597 if (dissolve_neighbour > 0 && outer_area <= 0) {
598 G_fatal_error(_("Area merging failed"));
599 }
600
601 /* attach all isles to outer or new area */
602 if (outer_area >= 0) {
603 for (i = 0; i < IList->n_values; i++) {
604 if (!Map->plus.Isle[IList->value[i]])
605 continue;
606 Map->plus.Isle[IList->value[i]]->area = outer_area;
607 if (outer_area > 0)
609 IList->value[i]);
610 }
611 }
612
613 nremoved++;
615 }
616
617 if (removed_area)
619
620 G_message(_("%d areas of total size %g removed"), nremoved, size_removed);
621
629
630 return (nremoved);
631}
#define NULL
Definition ccmath.h:32
void G_percent(long, long, int)
Print percent complete messages.
Definition percent.c:61
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_message(const char *,...) __attribute__((format(printf
int G_debug(int, const char *,...) __attribute__((format(printf
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
double Vect_line_length(const struct line_pnts *)
Calculate line length, 3D-length in case of 3D vector line.
Definition line.c:575
plus_t Vect_get_num_areas(struct Map_info *)
Get number of areas in vector map.
Definition level_two.c:87
int Vect_area_alive(struct Map_info *, int)
Check if area is alive or dead (topological level required)
int Vect_build_line_area(struct Map_info *, int, int)
Build area on given side of line (GV_LEFT or GV_RIGHT)
Definition build.c:72
int Vect_get_area_boundaries(struct Map_info *, int, struct ilist *)
Creates list of boundaries for given area.
void Vect_destroy_list(struct ilist *)
Frees all memory associated with a struct ilist, including the struct itself.
void Vect_destroy_cats_struct(struct line_cats *)
Frees all memory associated with line_cats structure, including the struct itself.
int Vect_list_append(struct ilist *, int)
Append new item to the end of list if not yet present.
int Vect_get_area_isle(struct Map_info *, int, int)
Returns isle id for area.
int Vect_read_line(struct Map_info *, struct line_pnts *, struct line_cats *, int)
Read vector feature (topological level required)
int Vect_get_area_num_isles(struct Map_info *, int)
Returns number of isles for given area.
int Vect_line_alive(struct Map_info *, int)
Check if feature is alive or dead (topological level required)
int Vect_get_isle_boundaries(struct Map_info *, int, struct ilist *)
Creates list of boundaries for given isle.
int Vect_delete_line(struct Map_info *, off_t)
Delete existing feature (topological level required)
struct line_cats * Vect_new_cats_struct(void)
Creates and initializes line_cats structure.
struct ilist * Vect_new_list(void)
Creates and initializes a struct ilist.
off_t Vect_write_line(struct Map_info *, int, const struct line_pnts *, const struct line_cats *)
Writes a new feature.
int Vect_get_area_centroid(struct Map_info *, int)
Returns centroid id for given area.
double Vect_get_area_area(struct Map_info *, int)
Returns area of area without areas of isles.
int V1_delete_line_nat(struct Map_info *, off_t)
Deletes feature at level 1 (internal use only)
Definition write_nat.c:248
int Vect_get_line_areas(struct Map_info *, int, int *, int *)
Get area id on the left and right side of the boundary.
Definition level_two.c:347
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_get_isle_area(struct Map_info *, int)
Returns area id for isle.
#define GV_CENTROID
#define GV_BOUNDARY
#define GV_RIGHT
#define GV_LEFT
Boundary side indicator left/right.
#define GV_FORMAT_NATIVE
Geometry data formats supported by lib Don't change GV_FORMAT_* values, this order is hardcoded in li...
Definition dig_defines.h:83
int dig_area_add_isle(struct Plus_head *, int, int)
Add isle to area if does not exist yet.
Definition plus_area.c:265
int dig_del_line(struct Plus_head *, int, double, double, double)
Delete line from Plus_head structure.
Definition plus_line.c:217
int dig_del_area(struct Plus_head *, int)
Delete area from Plus_head structure.
Definition plus_area.c:365
int dig_del_isle(struct Plus_head *, int)
Delete island from Plus_head structure.
Definition plus_area.c:781
#define _(str)
Definition glocale.h:10
double l
Definition r_raster.c:39
int Vect_remove_small_areas_nat(struct Map_info *, double, struct Map_info *, double *)
int Vect_remove_small_areas_ext(struct Map_info *, double, struct Map_info *, double *)
int Vect_remove_small_areas(struct Map_info *Map, double thresh, struct Map_info *Err, double *removed_area)
Remove small areas from the map map.
Vector map info.
Topological feature - node.
double x
X coordinate.
double z
Z coordinate (used only for 3D data)
double y
Y coordinate.
Boundary topology.
plus_t left
Area number to the left, negative for isle.
plus_t N1
Start node.
plus_t right
Area number to the right, negative for isle.
Centroid topology.
plus_t area
Area number, negative for duplicate centroid.
List of integers.
Definition gis.h:715
Feature category info.
Feature geometry info - coordinates.