remove_areas.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. /*!
  2. \file lib/vector/Vlib/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 <stdlib.h>
  11. #include <grass/vector.h>
  12. #include <grass/glocale.h>
  13. #define DEGUG_RMAREA
  14. int Vect_remove_small_areas_nat(struct Map_info *, double,
  15. struct Map_info *, double *);
  16. int Vect_remove_small_areas_ext(struct Map_info *, double,
  17. struct Map_info *, double *);
  18. /*!
  19. \brief Remove small areas from the map map.
  20. Centroid of the area and the longest boundary with adjacent area is
  21. removed. Map topology must be built GV_BUILD_CENTROIDS.
  22. \param[in,out] Map vector map
  23. \param thresh maximum area size for removed areas
  24. \param[out] Err vector map where removed lines and centroids are written
  25. \param removed_area pointer to where total size of removed area is stored or NULL
  26. \return number of removed areas
  27. */
  28. int
  29. Vect_remove_small_areas(struct Map_info *Map, double thresh,
  30. struct Map_info *Err, double *removed_area)
  31. {
  32. if (Map->format == GV_FORMAT_NATIVE)
  33. return Vect_remove_small_areas_nat(Map, thresh, Err, removed_area);
  34. else
  35. return Vect_remove_small_areas_ext(Map, thresh, Err, removed_area);
  36. }
  37. int
  38. Vect_remove_small_areas_ext(struct Map_info *Map, double thresh,
  39. struct Map_info *Err, double *removed_area)
  40. {
  41. int area, nareas;
  42. int nremoved = 0;
  43. struct ilist *List;
  44. struct ilist *AList;
  45. struct line_pnts *Points;
  46. struct line_cats *Cats;
  47. double size_removed = 0.0;
  48. List = Vect_new_list();
  49. AList = Vect_new_list();
  50. Points = Vect_new_line_struct();
  51. Cats = Vect_new_cats_struct();
  52. nareas = Vect_get_num_areas(Map);
  53. for (area = 1; area <= nareas; area++) {
  54. int i, j, centroid, dissolve_neighbour;
  55. double length, size;
  56. G_percent(area, nareas, 1);
  57. G_debug(3, "area = %d", area);
  58. if (!Vect_area_alive(Map, area))
  59. continue;
  60. size = Vect_get_area_area(Map, area);
  61. if (size > thresh)
  62. continue;
  63. size_removed += size;
  64. /* The area is smaller than the limit -> remove */
  65. /* Remove centroid */
  66. centroid = Vect_get_area_centroid(Map, area);
  67. if (centroid > 0) {
  68. if (Err) {
  69. Vect_read_line(Map, Points, Cats, centroid);
  70. Vect_write_line(Err, GV_CENTROID, Points, Cats);
  71. }
  72. Vect_delete_line(Map, centroid);
  73. }
  74. /* Find the adjacent area with which the longest boundary is shared */
  75. Vect_get_area_boundaries(Map, area, List);
  76. /* Create a list of neighbour areas */
  77. Vect_reset_list(AList);
  78. for (i = 0; i < List->n_values; i++) {
  79. int line, left, right, neighbour;
  80. line = List->value[i];
  81. if (!Vect_line_alive(Map, abs(line))) /* Should not happen */
  82. G_fatal_error(_("Area is composed of dead boundary"));
  83. Vect_get_line_areas(Map, abs(line), &left, &right);
  84. if (line > 0)
  85. neighbour = left;
  86. else
  87. neighbour = right;
  88. G_debug(4, " line = %d left = %d right = %d neighbour = %d",
  89. line, left, right, neighbour);
  90. Vect_list_append(AList, neighbour); /* this checks for duplicity */
  91. }
  92. G_debug(3, "num neighbours = %d", AList->n_values);
  93. /* Go through the list of neighours and find that with the longest boundary */
  94. dissolve_neighbour = 0;
  95. length = -1.0;
  96. for (i = 0; i < AList->n_values; i++) {
  97. int neighbour1;
  98. double l = 0.0;
  99. neighbour1 = AList->value[i];
  100. G_debug(4, " neighbour1 = %d", neighbour1);
  101. for (j = 0; j < List->n_values; j++) {
  102. int line, left, right, neighbour2;
  103. line = List->value[j];
  104. Vect_get_line_areas(Map, abs(line), &left, &right);
  105. if (line > 0)
  106. neighbour2 = left;
  107. else
  108. neighbour2 = right;
  109. if (neighbour2 == neighbour1) {
  110. Vect_read_line(Map, Points, NULL, abs(line));
  111. l += Vect_line_length(Points);
  112. }
  113. }
  114. if (l > length) {
  115. length = l;
  116. dissolve_neighbour = neighbour1;
  117. }
  118. }
  119. G_debug(3, "dissolve_neighbour = %d", dissolve_neighbour);
  120. /* Make list of boundaries to be removed */
  121. Vect_reset_list(AList);
  122. for (i = 0; i < List->n_values; i++) {
  123. int line, left, right, neighbour;
  124. line = List->value[i];
  125. Vect_get_line_areas(Map, abs(line), &left, &right);
  126. if (line > 0)
  127. neighbour = left;
  128. else
  129. neighbour = right;
  130. G_debug(3, " neighbour = %d", neighbour);
  131. if (neighbour == dissolve_neighbour) {
  132. Vect_list_append(AList, abs(line));
  133. }
  134. }
  135. /* Remove boundaries */
  136. for (i = 0; i < AList->n_values; i++) {
  137. int line;
  138. line = AList->value[i];
  139. if (Err) {
  140. Vect_read_line(Map, Points, Cats, line);
  141. Vect_write_line(Err, GV_BOUNDARY, Points, Cats);
  142. }
  143. Vect_delete_line(Map, line);
  144. }
  145. nremoved++;
  146. nareas = Vect_get_num_areas(Map);
  147. }
  148. if (removed_area)
  149. *removed_area = size_removed;
  150. G_message(_("%d areas of total size %g removed"), nremoved,
  151. size_removed);
  152. return (nremoved);
  153. }
  154. /* much faster version */
  155. int
  156. Vect_remove_small_areas_nat(struct Map_info *Map, double thresh,
  157. struct Map_info *Err, double *removed_area)
  158. {
  159. int area, nareas;
  160. int nremoved = 0;
  161. struct ilist *List;
  162. struct ilist *AList;
  163. struct ilist *BList;
  164. #ifdef DEGUG_RMAREA
  165. struct ilist *NList;
  166. #endif
  167. struct ilist *IList;
  168. struct line_pnts *Points;
  169. struct line_cats *Cats;
  170. double size_removed = 0.0;
  171. int dissolve_neighbour;
  172. int line, left, right, neighbour;
  173. int nisles, nnisles;
  174. List = Vect_new_list();
  175. AList = Vect_new_list();
  176. BList = Vect_new_list();
  177. #ifdef DEGUG_RMAREA
  178. NList = Vect_new_list();
  179. #endif
  180. IList = Vect_new_list();
  181. Points = Vect_new_line_struct();
  182. Cats = Vect_new_cats_struct();
  183. nareas = Vect_get_num_areas(Map);
  184. for (area = 1; area <= nareas; area++) {
  185. int i, j, centroid, ncentroid;
  186. double length, l, size;
  187. int outer_area = -1;
  188. int narea, same_atype = 0;
  189. G_percent(area, nareas, 1);
  190. G_debug(3, "area = %d", area);
  191. if (!Vect_area_alive(Map, area))
  192. continue;
  193. size = Vect_get_area_area(Map, area);
  194. if (size > thresh)
  195. continue;
  196. size_removed += size;
  197. /* The area is smaller than the limit -> remove */
  198. /* Remove centroid */
  199. centroid = Vect_get_area_centroid(Map, area);
  200. if (centroid > 0) {
  201. if (Err) {
  202. Vect_read_line(Map, Points, Cats, centroid);
  203. Vect_write_line(Err, GV_CENTROID, Points, Cats);
  204. }
  205. Vect_delete_line(Map, centroid);
  206. }
  207. /* Find the adjacent area with which the longest boundary is shared */
  208. Vect_get_area_boundaries(Map, area, List);
  209. /* Create a list of neighbour areas */
  210. Vect_reset_list(AList);
  211. for (i = 0; i < List->n_values; i++) {
  212. line = List->value[i];
  213. if (!Vect_line_alive(Map, abs(line))) /* Should not happen */
  214. G_fatal_error(_("Area is composed of dead boundary"));
  215. Vect_get_line_areas(Map, abs(line), &left, &right);
  216. if (line > 0)
  217. neighbour = left;
  218. else
  219. neighbour = right;
  220. G_debug(4, " line = %d left = %d right = %d neighbour = %d",
  221. line, left, right, neighbour);
  222. ncentroid = 0;
  223. if (neighbour > 0) {
  224. ncentroid = Vect_get_area_centroid(Map, neighbour);
  225. }
  226. if (neighbour < 0) {
  227. narea = Vect_get_isle_area(Map, -neighbour);
  228. if (narea > 0)
  229. ncentroid = Vect_get_area_centroid(Map, narea);
  230. }
  231. if ((centroid != 0) + (ncentroid != 0) != 1)
  232. same_atype = 1;
  233. Vect_list_append(AList, neighbour); /* this checks for duplicity */
  234. }
  235. G_debug(3, "num neighbours = %d", AList->n_values);
  236. if (AList->n_values == 1)
  237. same_atype = 0;
  238. /* Go through the list of neighbours and find the one with the longest boundary */
  239. dissolve_neighbour = 0;
  240. length = -1.0;
  241. for (i = 0; i < AList->n_values; i++) {
  242. int neighbour1;
  243. l = 0.0;
  244. neighbour1 = AList->value[i];
  245. G_debug(4, " neighbour1 = %d", neighbour1);
  246. if (same_atype) {
  247. ncentroid = 0;
  248. if (neighbour1 > 0) {
  249. ncentroid = Vect_get_area_centroid(Map, neighbour1);
  250. }
  251. if (neighbour1 < 0) {
  252. narea = Vect_get_isle_area(Map, -neighbour1);
  253. if (narea > 0)
  254. ncentroid = Vect_get_area_centroid(Map, narea);
  255. }
  256. if ((centroid != 0) + (ncentroid != 0) == 1)
  257. continue;
  258. }
  259. for (j = 0; j < List->n_values; j++) {
  260. int neighbour2;
  261. line = List->value[j];
  262. Vect_get_line_areas(Map, abs(line), &left, &right);
  263. if (line > 0)
  264. neighbour2 = left;
  265. else
  266. neighbour2 = right;
  267. if (neighbour2 == neighbour1) {
  268. Vect_read_line(Map, Points, NULL, abs(line));
  269. l += Vect_line_length(Points);
  270. }
  271. }
  272. if (l > length) {
  273. length = l;
  274. dissolve_neighbour = neighbour1;
  275. }
  276. }
  277. G_debug(3, "dissolve_neighbour = %d", dissolve_neighbour);
  278. if (dissolve_neighbour == 0) {
  279. G_fatal_error("could not find neighbour to dissolve");
  280. }
  281. /* Make list of boundaries to be removed */
  282. Vect_reset_list(AList);
  283. Vect_reset_list(BList);
  284. for (i = 0; i < List->n_values; i++) {
  285. line = List->value[i];
  286. Vect_get_line_areas(Map, abs(line), &left, &right);
  287. if (line > 0)
  288. neighbour = left;
  289. else
  290. neighbour = right;
  291. G_debug(3, " neighbour = %d", neighbour);
  292. if (neighbour == dissolve_neighbour) {
  293. Vect_list_append(AList, abs(line));
  294. }
  295. else
  296. Vect_list_append(BList, line);
  297. }
  298. G_debug(3, "remove %d of %d boundaries", AList->n_values, List->n_values);
  299. /* Get isles inside area */
  300. Vect_reset_list(IList);
  301. if ((nisles = Vect_get_area_num_isles(Map, area)) > 0) {
  302. for (i = 0; i < nisles; i++) {
  303. Vect_list_append(IList, Vect_get_area_isle(Map, area, i));
  304. }
  305. }
  306. /* Remove boundaries */
  307. for (i = 0; i < AList->n_values; i++) {
  308. int ret;
  309. line = AList->value[i];
  310. if (Err) {
  311. Vect_read_line(Map, Points, Cats, line);
  312. Vect_write_line(Err, GV_BOUNDARY, Points, Cats);
  313. }
  314. /* Vect_delete_line(Map, line); */
  315. /* delete the line from coor */
  316. ret = V1_delete_line_nat(Map, Map->plus.Line[line]->offset);
  317. if (ret == -1) {
  318. G_fatal_error(_("Could not delete line from coor"));
  319. }
  320. }
  321. /* update topo */
  322. if (dissolve_neighbour > 0) {
  323. G_debug(3, "dissolve with neighbour area");
  324. /* get neighbour centroid */
  325. centroid = Vect_get_area_centroid(Map, dissolve_neighbour);
  326. /* get neighbour isles */
  327. if ((nnisles = Vect_get_area_num_isles(Map, dissolve_neighbour)) > 0) {
  328. for (i = 0; i < nnisles; i++) {
  329. Vect_list_append(IList, Vect_get_area_isle(Map, dissolve_neighbour, i));
  330. }
  331. }
  332. #ifdef DEGUG_RMAREA
  333. /* get neighbour boundaries */
  334. Vect_get_area_boundaries(Map, dissolve_neighbour, NList);
  335. #endif
  336. /* delete area from topo */
  337. dig_del_area(&(Map->plus), area);
  338. /* delete neighbour area from topo */
  339. dig_del_area(&(Map->plus), dissolve_neighbour);
  340. /* delete boundaries from topo */
  341. for (i = 0; i < AList->n_values; i++) {
  342. struct P_topo_b *topo;
  343. struct P_node *Node;
  344. line = AList->value[i];
  345. topo = (struct P_topo_b *)Map->plus.Line[line]->topo;
  346. Node = Map->plus.Node[topo->N1];
  347. dig_del_line(&(Map->plus), line, Node->x, Node->y, Node->z);
  348. }
  349. /* rebuild neighbour area from leftover boundaries */
  350. for (i = 0; i < BList->n_values; i++) {
  351. struct P_topo_b *topo;
  352. line = BList->value[i];
  353. topo = Map->plus.Line[abs(line)]->topo;
  354. if (topo->left == 0 || topo->right == 0) {
  355. int new_isle;
  356. new_isle = Vect_build_line_area(Map, abs(line), (line > 0 ? GV_RIGHT : GV_LEFT));
  357. if (new_isle > 0) {
  358. outer_area = new_isle;
  359. /* reattach centroid */
  360. Map->plus.Area[outer_area]->centroid = centroid;
  361. if (centroid > 0) {
  362. struct P_topo_c *ctopo = Map->plus.Line[centroid]->topo;
  363. ctopo->area = outer_area;
  364. }
  365. }
  366. else {
  367. /* should not happen */
  368. G_warning(_("Failed to build new area"));
  369. }
  370. }
  371. /* check */
  372. if (topo->left == 0 || topo->right == 0)
  373. G_warning(_("Dissolve with neighbour area: corrupt topology"));
  374. }
  375. #ifdef DEGUG_RMAREA
  376. for (i = 0; i < NList->n_values; i++) {
  377. struct P_topo_b *topo;
  378. line = NList->value[i];
  379. if (!Vect_line_alive(Map, abs(line)))
  380. continue;
  381. topo = Map->plus.Line[abs(line)]->topo;
  382. if (topo->left == 0 || topo->right == 0) {
  383. int new_isle;
  384. G_warning(_("Neighbor boundaries should be complete"));
  385. new_isle = Vect_build_line_area(Map, abs(line), (line > 0 ? GV_RIGHT : GV_LEFT));
  386. if (new_isle > 0) {
  387. outer_area = new_isle;
  388. /* reattach centroid */
  389. Map->plus.Area[outer_area]->centroid = centroid;
  390. if (centroid > 0) {
  391. struct P_topo_c *ctopo = Map->plus.Line[centroid]->topo;
  392. ctopo->area = outer_area;
  393. }
  394. }
  395. else {
  396. /* should not happen */
  397. G_warning(_("Failed to build new area"));
  398. }
  399. }
  400. if (topo->left == 0 || topo->right == 0)
  401. G_warning(_("Dissolve with neighbour area: corrupt topology"));
  402. }
  403. #endif
  404. }
  405. /* dissolve with outer isle */
  406. else if (dissolve_neighbour < 0) {
  407. G_debug(3, "dissolve with outer isle");
  408. outer_area = Vect_get_isle_area(Map, -dissolve_neighbour);
  409. #ifdef DEGUG_RMAREA
  410. /* get isle boundaries */
  411. Vect_get_isle_boundaries(Map, -dissolve_neighbour, NList);
  412. #endif
  413. /* delete area from topo */
  414. dig_del_area(&(Map->plus), area);
  415. /* delete isle from topo */
  416. dig_del_isle(&(Map->plus), -dissolve_neighbour);
  417. /* delete boundaries from topo */
  418. for (i = 0; i < AList->n_values; i++) {
  419. struct P_topo_b *topo;
  420. struct P_node *Node;
  421. line = AList->value[i];
  422. topo = (struct P_topo_b *)Map->plus.Line[line]->topo;
  423. Node = Map->plus.Node[topo->N1];
  424. dig_del_line(&(Map->plus), line, Node->x, Node->y, Node->z);
  425. }
  426. /* rebuild isles from leftover boundaries */
  427. for (i = 0; i < BList->n_values; i++) {
  428. struct P_topo_b *topo;
  429. line = BList->value[i];
  430. topo = Map->plus.Line[abs(line)]->topo;
  431. if (topo->left == 0 || topo->right == 0) {
  432. int new_isle;
  433. new_isle = Vect_build_line_area(Map, abs(line), (line > 0 ? GV_RIGHT : GV_LEFT));
  434. if (new_isle < 0) {
  435. Vect_list_append(IList, -new_isle);
  436. }
  437. else {
  438. /* should not happen */
  439. G_warning(_("Failed to build new isle"));
  440. }
  441. }
  442. /* check */
  443. if (topo->left == 0 || topo->right == 0)
  444. G_warning(_("Dissolve with outer isle: corrupt topology"));
  445. }
  446. #ifdef DEGUG_RMAREA
  447. for (i = 0; i < NList->n_values; i++) {
  448. struct P_topo_b *topo;
  449. line = NList->value[i];
  450. if (!Vect_line_alive(Map, abs(line)))
  451. continue;
  452. topo = Map->plus.Line[abs(line)]->topo;
  453. if (topo->left == 0 || topo->right == 0) {
  454. int new_isle;
  455. G_warning(_("Neighbor boundaries should be complete"));
  456. new_isle = Vect_build_line_area(Map, abs(line), (line > 0 ? GV_RIGHT : GV_LEFT));
  457. if (new_isle < 0) {
  458. Vect_list_append(IList, -new_isle);
  459. }
  460. else {
  461. /* should not happen */
  462. G_warning(_("Failed to build new isle"));
  463. }
  464. }
  465. /* check */
  466. if (topo->left == 0 || topo->right == 0)
  467. G_warning(_("Dissolve with outer isle: corrupt topology"));
  468. }
  469. #endif
  470. }
  471. if (dissolve_neighbour > 0 && outer_area <= 0) {
  472. G_fatal_error(_("Area merging failed"));
  473. }
  474. /* attach all isles to outer or new area */
  475. if (outer_area >= 0) {
  476. for (i = 0; i < IList->n_values; i++) {
  477. Map->plus.Isle[IList->value[i]]->area = outer_area;
  478. if (outer_area > 0)
  479. dig_area_add_isle(&(Map->plus), outer_area, IList->value[i]);
  480. }
  481. }
  482. nremoved++;
  483. nareas = Vect_get_num_areas(Map);
  484. }
  485. if (removed_area)
  486. *removed_area = size_removed;
  487. G_message(_("%d areas of total size %g removed"), nremoved,
  488. size_removed);
  489. Vect_destroy_list(List);
  490. Vect_destroy_list(AList);
  491. Vect_destroy_list(BList);
  492. #ifdef DEGUG_RMAREA
  493. Vect_destroy_list(NList);
  494. #endif
  495. Vect_destroy_list(IList);
  496. Vect_destroy_line_struct(Points);
  497. Vect_destroy_cats_struct(Cats);
  498. return (nremoved);
  499. }