remove_areas.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /*!
  2. \file remove_areas.c
  3. \brief Vector library - clean geometry (remove small areas)
  4. Higher level functions for reading/writing/manipulating vectors.
  5. (C) 2001-2009 by the GRASS Development Team
  6. This program is free software under the GNU General Public License
  7. (>=v2). Read the file COPYING that comes with GRASS for details.
  8. \author Radim Blazek
  9. */
  10. #include <grass/config.h>
  11. #include <stdlib.h>
  12. #include <grass/gis.h>
  13. #include <grass/vector.h>
  14. #include <grass/glocale.h>
  15. /*!
  16. \brief Remove small areas from the map map.
  17. Centroid of the area and the longest boundary with adjacent area is
  18. removed. Map topology must be built GV_BUILD_CENTROIDS.
  19. \param[in,out] Map vector map
  20. \param thresh maximum area size for removed areas
  21. \param[out] Err vector map where removed lines and centroids are written
  22. \param removed_area pointer to where total size of removed area is stored or NULL
  23. \return number of removed areas
  24. */
  25. int
  26. Vect_remove_small_areas(struct Map_info *Map, double thresh,
  27. struct Map_info *Err, double *removed_area)
  28. {
  29. int area, nareas;
  30. int nremoved = 0;
  31. struct ilist *List;
  32. struct ilist *AList;
  33. struct line_pnts *Points;
  34. struct line_cats *Cats;
  35. double size_removed = 0.0;
  36. List = Vect_new_list();
  37. AList = Vect_new_list();
  38. Points = Vect_new_line_struct();
  39. Cats = Vect_new_cats_struct();
  40. nareas = Vect_get_num_areas(Map);
  41. for (area = 1; area <= Vect_get_num_areas(Map); area++) {
  42. int i, j, centroid, dissolve_neighbour;
  43. double length, size;
  44. if (area <= nareas)
  45. G_percent(area, nareas, 1);
  46. G_debug(3, "area = %d", area);
  47. if (!Vect_area_alive(Map, area))
  48. continue;
  49. size = Vect_get_area_area(Map, area);
  50. if (size > thresh)
  51. continue;
  52. size_removed += size;
  53. /* The area is smaller than the limit -> remove */
  54. /* Remove centroid */
  55. centroid = Vect_get_area_centroid(Map, area);
  56. if (centroid > 0) {
  57. if (Err) {
  58. Vect_read_line(Map, Points, Cats, centroid);
  59. Vect_write_line(Err, GV_CENTROID, Points, Cats);
  60. }
  61. Vect_delete_line(Map, centroid);
  62. }
  63. /* Find the adjacent area with which the longest boundary is shared */
  64. Vect_get_area_boundaries(Map, area, List);
  65. /* Create a list of neighbour areas */
  66. Vect_reset_list(AList);
  67. for (i = 0; i < List->n_values; i++) {
  68. int line, left, right, neighbour;
  69. line = List->value[i];
  70. if (!Vect_line_alive(Map, abs(line))) /* Should not happen */
  71. G_fatal_error(_("Area is composed of dead boundary"));
  72. Vect_get_line_areas(Map, abs(line), &left, &right);
  73. if (line > 0)
  74. neighbour = left;
  75. else
  76. neighbour = right;
  77. G_debug(4, " line = %d left = %d right = %d neighbour = %d",
  78. line, left, right, neighbour);
  79. Vect_list_append(AList, neighbour); /* this checks for duplicity */
  80. }
  81. G_debug(3, "num neighbours = %d", AList->n_values);
  82. /* Go through the list of neghours and find that with the longest boundary */
  83. dissolve_neighbour = 0;
  84. length = -1.0;
  85. for (i = 0; i < AList->n_values; i++) {
  86. int neighbour1;
  87. double l = 0.0;
  88. neighbour1 = AList->value[i];
  89. G_debug(4, " neighbour1 = %d", neighbour1);
  90. for (j = 0; j < List->n_values; j++) {
  91. int line, left, right, neighbour2;
  92. line = List->value[j];
  93. Vect_get_line_areas(Map, abs(line), &left, &right);
  94. if (line > 0)
  95. neighbour2 = left;
  96. else
  97. neighbour2 = right;
  98. if (neighbour2 == neighbour1) {
  99. Vect_read_line(Map, Points, NULL, abs(line));
  100. l += Vect_line_length(Points);
  101. }
  102. }
  103. if (l > length) {
  104. length = l;
  105. dissolve_neighbour = neighbour1;
  106. }
  107. }
  108. G_debug(3, "dissolve_neighbour = %d", dissolve_neighbour);
  109. /* Make list of boundaries to be removed */
  110. Vect_reset_list(AList);
  111. for (i = 0; i < List->n_values; i++) {
  112. int line, left, right, neighbour;
  113. line = List->value[i];
  114. Vect_get_line_areas(Map, abs(line), &left, &right);
  115. if (line > 0)
  116. neighbour = left;
  117. else
  118. neighbour = right;
  119. G_debug(3, " neighbour = %d", neighbour);
  120. if (neighbour == dissolve_neighbour) {
  121. Vect_list_append(AList, abs(line));
  122. }
  123. }
  124. /* Remove boundaries */
  125. for (i = 0; i < AList->n_values; i++) {
  126. int line;
  127. line = AList->value[i];
  128. if (Err) {
  129. Vect_read_line(Map, Points, Cats, line);
  130. Vect_write_line(Err, GV_BOUNDARY, Points, Cats);
  131. }
  132. Vect_delete_line(Map, line);
  133. }
  134. nremoved++;
  135. }
  136. if (removed_area)
  137. *removed_area = size_removed;
  138. G_verbose_message(_("%d areas of total size %g removed"), nremoved,
  139. size_removed);
  140. return (nremoved);
  141. }