GRASS 8 Programmer's Manual 8.6.0dev(2026)-1878fdfec5
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 SPDX-FileCopyrightText: 2001-2009 GRASS Development Team
9 SPDX-License-Identifier: GPL-2.0-or-later
10
11 \author Radim Blazek, Markus Metz
12 */
13
14#include <stdlib.h>
15#include <grass/vector.h>
16#include <grass/glocale.h>
17
18int Vect_remove_small_areas_nat(struct Map_info *, double, struct Map_info *,
19 double *);
20
21int Vect_remove_small_areas_ext(struct Map_info *, double, struct Map_info *,
22 double *);
23
24/*!
25 \brief Remove small areas from the map map.
26
27 Centroid of the area and the longest boundary with adjacent area is
28 removed. Map topology must be built GV_BUILD_CENTROIDS.
29
30 \param[in,out] Map vector map
31 \param thresh maximum area size for removed areas
32 \param[out] Err vector map where removed lines and centroids are written
33 \param removed_area pointer to where total size of removed area is stored or
34 NULL
35
36 \return number of removed areas
37 */
39 struct Map_info *Err, double *removed_area)
40{
41
42 if (Map->format == GV_FORMAT_NATIVE)
44 else
46}
47
49 struct Map_info *Err, double *removed_area)
50{
51 int area, nareas;
52 int nremoved = 0;
53 struct ilist *List;
54 struct ilist *AList;
55 struct line_pnts *Points;
56 struct line_cats *Cats;
57 double size_removed = 0.0;
58
61 Points = Vect_new_line_struct();
63
65 for (area = 1; area <= nareas; area++) {
66 int i, j, centroid, dissolve_neighbour;
67 double length, size;
68
69 G_percent(area, nareas, 1);
70 G_debug(3, "area = %d", area);
71 if (!Vect_area_alive(Map, area))
72 continue;
73
74 size = Vect_get_area_area(Map, area);
75 if (size > thresh)
76 continue;
77 size_removed += size;
78
79 /* The area is smaller than the limit -> remove */
80
81 /* Remove centroid */
82 centroid = Vect_get_area_centroid(Map, area);
83 if (centroid > 0) {
84 if (Err) {
85 Vect_read_line(Map, Points, Cats, centroid);
87 }
88 Vect_delete_line(Map, centroid);
89 }
90
91 /* Find the adjacent area with which the longest boundary is shared */
92
94
95 /* Create a list of neighbour areas */
97 for (i = 0; i < List->n_values; i++) {
98 int line, left, right, neighbour;
99
100 line = List->value[i];
101
102 if (!Vect_line_alive(Map, abs(line))) /* Should not happen */
103 G_fatal_error(_("Area is composed of dead boundary"));
104
105 Vect_get_line_areas(Map, abs(line), &left, &right);
106 if (line > 0)
107 neighbour = left;
108 else
109 neighbour = right;
110
111 G_debug(4, " line = %d left = %d right = %d neighbour = %d", line,
112 left, right, neighbour);
113
114 Vect_list_append(AList, neighbour); /* this checks for duplicity */
115 }
116 G_debug(3, "num neighbours = %d", AList->n_values);
117
118 /* Go through the list of neighbours and find that with the longest
119 * boundary */
121 length = -1.0;
122 for (i = 0; i < AList->n_values; i++) {
123 int neighbour1;
124 double l = 0.0;
125
126 neighbour1 = AList->value[i];
127 G_debug(4, " neighbour1 = %d", neighbour1);
128
129 for (j = 0; j < List->n_values; j++) {
130 int line, left, right, neighbour2;
131
132 line = List->value[j];
133 Vect_get_line_areas(Map, abs(line), &left, &right);
134 if (line > 0)
135 neighbour2 = left;
136 else
137 neighbour2 = right;
138
139 if (neighbour2 == neighbour1) {
140 Vect_read_line(Map, Points, NULL, abs(line));
141 l += Vect_line_length(Points);
142 }
143 }
144 if (l > length) {
145 length = l;
147 }
148 }
149
150 G_debug(3, "dissolve_neighbour = %d", dissolve_neighbour);
151
152 /* Make list of boundaries to be removed */
154 for (i = 0; i < List->n_values; i++) {
155 int line, left, right, neighbour;
156
157 line = List->value[i];
158 Vect_get_line_areas(Map, abs(line), &left, &right);
159 if (line > 0)
160 neighbour = left;
161 else
162 neighbour = right;
163
164 G_debug(3, " neighbour = %d", neighbour);
165
167 Vect_list_append(AList, abs(line));
168 }
169 }
170
171 /* Remove boundaries */
172 for (i = 0; i < AList->n_values; i++) {
173 int line;
174
175 line = AList->value[i];
176
177 if (Err) {
178 Vect_read_line(Map, Points, Cats, line);
180 }
181 Vect_delete_line(Map, line);
182 }
183
184 nremoved++;
186 }
187
188 if (removed_area)
190
191 G_message(_("%d areas of total size %g removed"), nremoved, size_removed);
196
197 return (nremoved);
198}
199
200/* much faster version */
202 struct Map_info *Err, double *removed_area)
203{
204 int area, nareas;
205 int nremoved = 0;
206 struct ilist *List;
207 struct ilist *AList;
208 struct ilist *BList;
209 struct ilist *NList;
210 struct ilist *IList;
211 struct line_pnts *Points;
212 struct line_cats *Cats;
213 double size_removed = 0.0;
215 int line, left, right, neighbour;
216 int nisles, nnisles;
217
223 Points = Vect_new_line_struct();
225
227 for (area = 1; area <= nareas; area++) {
228 int i, j, centroid, ncentroid;
229 double length, l, size;
230 int outer_area = -1;
231 int narea, same_atype = 0;
232
233 G_percent(area, nareas, 1);
234 G_debug(3, "area = %d", area);
235 if (!Vect_area_alive(Map, area))
236 continue;
237
238 size = Vect_get_area_area(Map, area);
239 if (size > thresh)
240 continue;
241 size_removed += size;
242
243 /* The area is smaller than the limit -> remove */
244
245 /* Remove centroid */
246 centroid = Vect_get_area_centroid(Map, area);
247 if (centroid > 0) {
248 if (Err) {
249 Vect_read_line(Map, Points, Cats, centroid);
251 }
252 Vect_delete_line(Map, centroid);
253 }
254
255 /* Find the adjacent area with which the longest boundary is shared */
256
258
259 /* Create a list of neighbour areas */
261 for (i = 0; i < List->n_values; i++) {
262
263 line = List->value[i];
264
265 if (!Vect_line_alive(Map, abs(line))) /* Should not happen */
266 G_fatal_error(_("Area is composed of dead boundary"));
267
268 Vect_get_line_areas(Map, abs(line), &left, &right);
269 if (line > 0)
270 neighbour = left;
271 else
272 neighbour = right;
273
274 G_debug(4, " line = %d left = %d right = %d neighbour = %d", line,
275 left, right, neighbour);
276
277 ncentroid = 0;
278 if (neighbour > 0) {
280 }
281 if (neighbour < 0) {
283 if (narea > 0)
285 }
286 if ((centroid != 0) + (ncentroid != 0) != 1)
287 same_atype = 1;
288
289 Vect_list_append(AList, neighbour); /* this checks for duplicity */
290 }
291 G_debug(3, "num neighbours = %d", AList->n_values);
292
293 if (AList->n_values == 1)
294 same_atype = 0;
295
296 /* Go through the list of neighbours and find the one with the longest
297 * boundary */
299 length = -1.0;
300 for (i = 0; i < AList->n_values; i++) {
301 int neighbour1;
302
303 l = 0.0;
304 neighbour1 = AList->value[i];
305 G_debug(4, " neighbour1 = %d", neighbour1);
306
307 if (same_atype) {
308 ncentroid = 0;
309 if (neighbour1 > 0) {
311 }
312 if (neighbour1 < 0) {
314 if (narea > 0)
316 }
317 if ((centroid != 0) + (ncentroid != 0) == 1)
318 continue;
319 }
320
321 for (j = 0; j < List->n_values; j++) {
322 int neighbour2;
323
324 line = List->value[j];
325 Vect_get_line_areas(Map, abs(line), &left, &right);
326 if (line > 0)
327 neighbour2 = left;
328 else
329 neighbour2 = right;
330
331 if (neighbour2 == neighbour1) {
332 Vect_read_line(Map, Points, NULL, abs(line));
333 l += Vect_line_length(Points);
334 }
335 }
336 if (l > length) {
337 length = l;
339 }
340 }
341
342 G_debug(3, "dissolve_neighbour = %d", dissolve_neighbour);
343
344 if (dissolve_neighbour == 0) {
345 G_fatal_error("could not find neighbour to dissolve");
346 }
347
348 /* Make list of boundaries to be removed */
351 for (i = 0; i < List->n_values; i++) {
352
353 line = List->value[i];
354 Vect_get_line_areas(Map, abs(line), &left, &right);
355 if (line > 0)
356 neighbour = left;
357 else
358 neighbour = right;
359
360 G_debug(3, " neighbour = %d", neighbour);
361
363 Vect_list_append(AList, abs(line));
364 }
365 else
366 Vect_list_append(BList, line);
367 }
368 G_debug(3, "remove %d of %d boundaries", AList->n_values,
369 List->n_values);
370
371 /* Get isles inside area */
373 if ((nisles = Vect_get_area_num_isles(Map, area)) > 0) {
374 for (i = 0; i < nisles; i++) {
376 }
377 }
378
379 /* Remove boundaries */
380 for (i = 0; i < AList->n_values; i++) {
381 int ret;
382
383 line = AList->value[i];
384
385 if (Err) {
386 Vect_read_line(Map, Points, Cats, line);
388 }
389 /* Vect_delete_line(Map, line); */
390
391 /* delete the line from coor */
392 ret = V1_delete_line_nat(Map, Map->plus.Line[line]->offset);
393
394 if (ret == -1) {
395 G_fatal_error(_("Could not delete line from coor"));
396 }
397 }
398
399 /* update topo */
400 if (dissolve_neighbour > 0) {
401
402 G_debug(3, "dissolve with neighbour area");
403
404 /* get neighbour centroid */
406 /* get neighbour isles */
408 0) {
409 for (i = 0; i < nnisles; i++) {
412 }
413 }
414
415 /* get neighbour boundaries */
417
418 /* delete area from topo */
419 dig_del_area(&(Map->plus), area);
420 /* delete neighbour area from topo */
422 /* delete boundaries from topo */
423 for (i = 0; i < AList->n_values; i++) {
424 struct P_topo_b *topo;
425 struct P_node *Node;
426
427 line = AList->value[i];
428 topo = (struct P_topo_b *)Map->plus.Line[line]->topo;
429 Node = Map->plus.Node[topo->N1];
430 dig_del_line(&(Map->plus), line, Node->x, Node->y, Node->z);
431 }
432 /* build new area from leftover boundaries of deleted area */
433 for (i = 0; i < BList->n_values; i++) {
434 struct P_topo_b *topo;
435 int new_isle;
436
437 line = BList->value[i];
438 topo = Map->plus.Line[abs(line)]->topo;
439
440 if (topo->left == 0 || topo->right == 0) {
442 Map, abs(line), (line > 0 ? GV_RIGHT : GV_LEFT));
443 if (new_isle > 0) {
444 if (outer_area > 0)
445 G_fatal_error("dissolve_neighbour > 0, new area "
446 "has already been created");
448 /* reattach centroid */
449 Map->plus.Area[outer_area]->centroid = centroid;
450 if (centroid > 0) {
451 struct P_topo_c *ctopo =
452 Map->plus.Line[centroid]->topo;
453
454 ctopo->area = outer_area;
455 }
456 }
457 else if (new_isle < 0) {
458 /* leftover boundary creates a new isle */
460 }
461 else {
462 /* neither area nor isle, should not happen */
463 G_fatal_error(_("dissolve_neighbour > 0, failed to "
464 "build new area"));
465 }
466 }
467 /* check */
468 if (topo->left == 0 || topo->right == 0)
470 _("Dissolve with neighbour area: corrupt topology"));
471 }
472 /* build new area from neighbour's boundaries */
473 for (i = 0; i < NList->n_values; i++) {
474 struct P_topo_b *topo;
475
476 line = NList->value[i];
477 if (!Vect_line_alive(Map, abs(line)))
478 continue;
479
480 topo = Map->plus.Line[abs(line)]->topo;
481
482 if (topo->left == 0 || topo->right == 0) {
483 int new_isle;
484
486 Map, abs(line), (line > 0 ? GV_RIGHT : GV_LEFT));
487 if (new_isle > 0) {
488 if (outer_area > 0)
489 G_fatal_error("dissolve_neighbour > 0, new area "
490 "has already been created");
492 /* reattach centroid */
493 Map->plus.Area[outer_area]->centroid = centroid;
494 if (centroid > 0) {
495 struct P_topo_c *ctopo =
496 Map->plus.Line[centroid]->topo;
497
498 ctopo->area = outer_area;
499 }
500 }
501 else if (new_isle < 0) {
502 /* Neigbour's boundary creates a new isle */
504 }
505 else {
506 /* neither area nor isle, should not happen */
507 G_fatal_error(_("Failed to build new area"));
508 }
509 }
510 if (topo->left == 0 || topo->right == 0)
512 _("Dissolve with neighbour area: corrupt topology"));
513 }
514 }
515 /* dissolve with outer isle */
516 else if (dissolve_neighbour < 0) {
517
518 G_debug(3, "dissolve with outer isle");
519
521
522 /* get isle boundaries */
524
525 /* delete area from topo */
526 dig_del_area(&(Map->plus), area);
527 /* delete isle from topo */
529 /* delete boundaries from topo */
530 for (i = 0; i < AList->n_values; i++) {
531 struct P_topo_b *topo;
532 struct P_node *Node;
533
534 line = AList->value[i];
535 topo = (struct P_topo_b *)Map->plus.Line[line]->topo;
536 Node = Map->plus.Node[topo->N1];
537 dig_del_line(&(Map->plus), line, Node->x, Node->y, Node->z);
538 }
539 /* build new isle(s) from leftover boundaries */
540 for (i = 0; i < BList->n_values; i++) {
541 struct P_topo_b *topo;
542
543 line = BList->value[i];
544 topo = Map->plus.Line[abs(line)]->topo;
545
546 if (topo->left == 0 || topo->right == 0) {
547 int new_isle;
548
550 Map, abs(line), (line > 0 ? GV_RIGHT : GV_LEFT));
551 if (new_isle < 0) {
553 }
554 else {
555 /* area or nothing should not happen */
556 G_fatal_error(_("Failed to build new isle"));
557 }
558 }
559 /* check */
560 if (topo->left == 0 || topo->right == 0)
562 _("Dissolve with outer isle: corrupt topology"));
563 }
564
565 /* build new isle(s) from old isle's boundaries */
566 for (i = 0; i < NList->n_values; i++) {
567 struct P_topo_b *topo;
568
569 line = NList->value[i];
570 if (!Vect_line_alive(Map, abs(line)))
571 continue;
572
573 topo = Map->plus.Line[abs(line)]->topo;
574
575 if (topo->left == 0 || topo->right == 0) {
576 int new_isle;
577
579 Map, abs(line), (line > 0 ? GV_RIGHT : GV_LEFT));
580 if (new_isle < 0) {
582 }
583 else {
584 /* area or nothing should not happen */
585 G_fatal_error(_("Failed to build new isle"));
586 }
587 }
588 /* check */
589 if (topo->left == 0 || topo->right == 0)
591 _("Dissolve with outer isle: corrupt topology"));
592 }
593 }
594
595 if (dissolve_neighbour > 0 && outer_area <= 0) {
596 G_fatal_error(_("Area merging failed"));
597 }
598
599 /* attach all isles to outer or new area */
600 if (outer_area >= 0) {
601 for (i = 0; i < IList->n_values; i++) {
602 if (!Map->plus.Isle[IList->value[i]])
603 continue;
604 Map->plus.Isle[IList->value[i]]->area = outer_area;
605 if (outer_area > 0)
607 IList->value[i]);
608 }
609 }
610
611 nremoved++;
613 }
614
615 if (removed_area)
617
618 G_message(_("%d areas of total size %g removed"), nremoved, size_removed);
619
627
628 return (nremoved);
629}
#define NULL
Definition ccmath.h:32
void G_percent(long, long, int)
Print percent complete messages.
Definition percent.c:59
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:75
double Vect_line_length(const struct line_pnts *)
Calculate line length, 3D-length in case of 3D vector line.
Definition line.c:573
plus_t Vect_get_num_areas(struct Map_info *)
Get number of areas in vector map.
Definition level_two.c:85
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:70
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:246
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:345
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_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:37
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:712
Feature category info.
Feature geometry info - coordinates.