remove_areas.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  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 neighours 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. Vect_build_partial(Map, GV_BUILD_BASE);
  141. Vect_merge_lines(Map, GV_BOUNDARY, NULL, NULL);
  142. return (nremoved);
  143. }
  144. /* faster version */
  145. int
  146. Vect_remove_small_areas_faster(struct Map_info *Map, double thresh,
  147. struct Map_info *Err, double *removed_area)
  148. {
  149. int area, nareas;
  150. int nremoved = 0;
  151. struct ilist *List;
  152. struct ilist *AList;
  153. struct line_pnts *Points;
  154. struct line_cats *Cats;
  155. double size_removed = 0.0;
  156. int left, right, dissolve_neighbour;
  157. List = Vect_new_list();
  158. AList = Vect_new_list();
  159. Points = Vect_new_line_struct();
  160. Cats = Vect_new_cats_struct();
  161. nareas = Vect_get_num_areas(Map);
  162. for (area = 1; area <= Vect_get_num_areas(Map); area++) {
  163. int i, centroid, remove_boundary;
  164. double length, size;
  165. if (area <= nareas)
  166. G_percent(area, nareas, 1);
  167. G_debug(3, "area = %d", area);
  168. if (!Vect_area_alive(Map, area))
  169. continue;
  170. size = Vect_get_area_area(Map, area);
  171. if (size > thresh)
  172. continue;
  173. size_removed += size;
  174. /* The area is smaller than the limit -> remove */
  175. /* Remove centroid */
  176. centroid = Vect_get_area_centroid(Map, area);
  177. if (centroid > 0) {
  178. if (Err) {
  179. Vect_read_line(Map, Points, Cats, centroid);
  180. Vect_write_line(Err, GV_CENTROID, Points, Cats);
  181. }
  182. Vect_delete_line(Map, centroid);
  183. }
  184. /* Find the adjacent area with which the longest boundary is shared */
  185. Vect_get_area_boundaries(Map, area, List);
  186. /* Go through the list of boundaries and find the longest boundary */
  187. remove_boundary = 0;
  188. length = -1.0;
  189. for (i = 0; i < List->n_values; i++) {
  190. int line;
  191. double l = 0.0;
  192. line = List->value[i];
  193. G_debug(4, " line = %d", line);
  194. Vect_read_line(Map, Points, NULL, abs(line));
  195. l = Vect_line_length(Points);
  196. if (l > length) {
  197. length = l;
  198. remove_boundary = line;
  199. }
  200. }
  201. G_debug(3, "remove_boundary = %d", remove_boundary);
  202. Vect_get_line_areas(Map, abs(remove_boundary), &left, &right);
  203. dissolve_neighbour = 0;
  204. if (remove_boundary > 0)
  205. dissolve_neighbour = left;
  206. else
  207. dissolve_neighbour = right;
  208. G_debug(3, "dissolve_neighbour = %d", dissolve_neighbour);
  209. G_debug(3, "dissolve_neighbour = %d", dissolve_neighbour);
  210. if (dissolve_neighbour == 0)
  211. G_fatal_error("could not find neighbour to dissolve");
  212. /* Make list of boundaries to be removed */
  213. Vect_reset_list(AList);
  214. for (i = 0; i < List->n_values; i++) {
  215. int line, neighbour;
  216. line = List->value[i];
  217. Vect_get_line_areas(Map, abs(line), &left, &right);
  218. if (line > 0)
  219. neighbour = left;
  220. else
  221. neighbour = right;
  222. G_debug(3, " neighbour = %d", neighbour);
  223. if (neighbour == dissolve_neighbour) {
  224. Vect_list_append(AList, abs(line));
  225. }
  226. }
  227. /* Remove boundaries */
  228. for (i = 0; i < AList->n_values; i++) {
  229. int line;
  230. line = AList->value[i];
  231. if (Err) {
  232. Vect_read_line(Map, Points, Cats, line);
  233. Vect_write_line(Err, GV_BOUNDARY, Points, Cats);
  234. }
  235. Vect_delete_line(Map, line);
  236. }
  237. nremoved++;
  238. }
  239. if (removed_area)
  240. *removed_area = size_removed;
  241. G_verbose_message(_("%d areas of total size %g removed"), nremoved,
  242. size_removed);
  243. Vect_build_partial(Map, GV_BUILD_BASE);
  244. Vect_merge_lines(Map, GV_BOUNDARY, NULL, NULL);
  245. return (nremoved);
  246. }
  247. /* much faster version */
  248. int
  249. Vect_remove_small_areas_fastest(struct Map_info *Map, double thresh,
  250. struct Map_info *Err, double *removed_area)
  251. {
  252. int area, nareas;
  253. int nremoved = 0;
  254. struct ilist *List;
  255. struct ilist *AList;
  256. struct ilist *BList;
  257. struct ilist *NList;
  258. struct ilist *IList;
  259. struct line_pnts *Points;
  260. struct line_cats *Cats;
  261. double size_removed = 0.0;
  262. int dissolve_neighbour;
  263. int line, left, right, neighbour;
  264. int nisles, nnisles;
  265. List = Vect_new_list();
  266. AList = Vect_new_list();
  267. BList = Vect_new_list();
  268. NList = Vect_new_list();
  269. IList = Vect_new_list();
  270. Points = Vect_new_line_struct();
  271. Cats = Vect_new_cats_struct();
  272. nareas = Vect_get_num_areas(Map);
  273. for (area = 1; area <= Vect_get_num_areas(Map); area++) {
  274. int i, j, centroid;
  275. double length, l, size;
  276. int outer_isle = 1, outer_area = -1;
  277. if (area <= nareas)
  278. G_percent(area, nareas, 1);
  279. G_debug(3, "area = %d", area);
  280. if (!Vect_area_alive(Map, area))
  281. continue;
  282. size = Vect_get_area_area(Map, area);
  283. if (size > thresh)
  284. continue;
  285. size_removed += size;
  286. /* The area is smaller than the limit -> remove */
  287. /* Remove centroid */
  288. centroid = Vect_get_area_centroid(Map, area);
  289. if (centroid > 0) {
  290. if (Err) {
  291. Vect_read_line(Map, Points, Cats, centroid);
  292. Vect_write_line(Err, GV_CENTROID, Points, Cats);
  293. }
  294. Vect_delete_line(Map, centroid);
  295. }
  296. /* Find the adjacent area with which the longest boundary is shared */
  297. Vect_get_area_boundaries(Map, area, List);
  298. /* Create a list of neighbour areas */
  299. Vect_reset_list(AList);
  300. for (i = 0; i < List->n_values; i++) {
  301. line = List->value[i];
  302. if (!Vect_line_alive(Map, abs(line))) /* Should not happen */
  303. G_fatal_error(_("Area is composed of dead boundary"));
  304. Vect_get_line_areas(Map, abs(line), &left, &right);
  305. if (line > 0)
  306. neighbour = left;
  307. else
  308. neighbour = right;
  309. G_debug(4, " line = %d left = %d right = %d neighbour = %d",
  310. line, left, right, neighbour);
  311. Vect_list_append(AList, neighbour); /* this checks for duplicity */
  312. }
  313. G_debug(3, "num neighbours = %d", AList->n_values);
  314. /* Go through the list of neighbours and find the one with the longest boundary */
  315. dissolve_neighbour = 0;
  316. length = -1.0;
  317. for (i = 0; i < AList->n_values; i++) {
  318. int neighbour1;
  319. l = 0.0;
  320. neighbour1 = AList->value[i];
  321. G_debug(4, " neighbour1 = %d", neighbour1);
  322. for (j = 0; j < List->n_values; j++) {
  323. int neighbour2;
  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. if (neighbour2 == neighbour1) {
  331. Vect_read_line(Map, Points, NULL, abs(line));
  332. l += Vect_line_length(Points);
  333. }
  334. }
  335. if (l > length) {
  336. length = l;
  337. dissolve_neighbour = neighbour1;
  338. }
  339. }
  340. G_debug(3, "dissolve_neighbour = %d", dissolve_neighbour);
  341. if (dissolve_neighbour == 0) {
  342. G_fatal_error("could not find neighbour to dissolve");
  343. }
  344. /* Make list of boundaries to be removed */
  345. Vect_reset_list(AList);
  346. Vect_reset_list(BList);
  347. for (i = 0; i < List->n_values; i++) {
  348. line = List->value[i];
  349. Vect_get_line_areas(Map, abs(line), &left, &right);
  350. if (line > 0)
  351. neighbour = left;
  352. else
  353. neighbour = right;
  354. G_debug(3, " neighbour = %d", neighbour);
  355. if (neighbour == dissolve_neighbour) {
  356. Vect_list_append(AList, abs(line));
  357. }
  358. else
  359. Vect_list_append(BList, line);
  360. if (neighbour < 0) {
  361. if (outer_isle > 0)
  362. outer_isle = neighbour;
  363. else if (outer_isle != neighbour)
  364. G_fatal_error("Two different isles outside area");
  365. }
  366. }
  367. G_debug(3, "remove %d of %d boundaries", AList->n_values, List->n_values);
  368. /* Get isles inside area */
  369. Vect_reset_list(IList);
  370. if ((nisles = Vect_get_area_num_isles(Map, area)) > 0) {
  371. for (i = 0; i < nisles; i++) {
  372. Vect_list_append(IList, Vect_get_area_isle(Map, area, i));
  373. }
  374. }
  375. /* Remove boundaries */
  376. for (i = 0; i < AList->n_values; i++) {
  377. int ret;
  378. line = AList->value[i];
  379. if (Err) {
  380. Vect_read_line(Map, Points, Cats, line);
  381. Vect_write_line(Err, GV_BOUNDARY, Points, Cats);
  382. }
  383. /* Vect_delete_line(Map, line); */
  384. /* delete the line from coor */
  385. ret = V1_delete_line_nat(Map, Map->plus.Line[line]->offset);
  386. if (ret == -1) {
  387. G_fatal_error("Could not delete line from coor");
  388. }
  389. }
  390. /* update topo */
  391. if (outer_isle < 0) {
  392. /* outer area */
  393. outer_area = Vect_get_isle_area(Map, -outer_isle);
  394. }
  395. if (dissolve_neighbour > 0) {
  396. int nareas_old;
  397. G_debug(3, "dissolve with neighbour area");
  398. /* get neighbour centroid */
  399. centroid = Vect_get_area_centroid(Map, dissolve_neighbour);
  400. /* get neighbour isles */
  401. if ((nnisles = Vect_get_area_num_isles(Map, dissolve_neighbour)) > 0) {
  402. for (i = 0; i < nnisles; i++) {
  403. Vect_list_append(IList, Vect_get_area_isle(Map, dissolve_neighbour, i));
  404. }
  405. }
  406. /* get neighbour boundaries */
  407. Vect_get_area_boundaries(Map, dissolve_neighbour, NList);
  408. /* delete area from topo */
  409. dig_del_area(&(Map->plus), area);
  410. /* delete neighbour area from topo */
  411. dig_del_area(&(Map->plus), dissolve_neighbour);
  412. /* delete boundaries from topo */
  413. for (i = 0; i < AList->n_values; i++) {
  414. line = AList->value[i];
  415. dig_del_line(&(Map->plus), line);
  416. }
  417. /* rebuild neighbour area from leftover boundaries */
  418. nareas_old = Vect_get_num_areas(Map);
  419. for (i = 0; i < BList->n_values; i++) {
  420. line = BList->value[i];
  421. if (Map->plus.Line[abs(line)]->left == 0 || Map->plus.Line[abs(line)]->right == 0) {
  422. int new_isle;
  423. new_isle = Vect_build_line_area(Map, abs(line), (line > 0 ? GV_RIGHT : GV_LEFT));
  424. if (new_isle > 0) {
  425. outer_area = new_isle;
  426. /* reattach centroid */
  427. Map->plus.Area[outer_area]->centroid = centroid;
  428. if (centroid > 0)
  429. Map->plus.Line[centroid]->left = outer_area;
  430. }
  431. else if (new_isle < 0) {
  432. Vect_list_append(IList, -new_isle);
  433. }
  434. }
  435. /* check */
  436. if (Map->plus.Line[abs(line)]->left == 0 || Map->plus.Line[abs(line)]->right == 0)
  437. G_fatal_error("dissolve with neighbour area: corrupt topology");
  438. }
  439. for (i = 0; i < NList->n_values; i++) {
  440. line = NList->value[i];
  441. if (!Vect_line_alive(Map, abs(line)))
  442. continue;
  443. if (Map->plus.Line[abs(line)]->left == 0 || Map->plus.Line[abs(line)]->right == 0) {
  444. int new_isle;
  445. new_isle = Vect_build_line_area(Map, abs(line), (line > 0 ? GV_RIGHT : GV_LEFT));
  446. if (new_isle > 0) {
  447. if (outer_area < 0) {
  448. outer_area = new_isle;
  449. /* reattach centroid */
  450. Map->plus.Area[outer_area]->centroid = centroid;
  451. if (centroid > 0)
  452. Map->plus.Line[centroid]->left = outer_area;
  453. }
  454. else
  455. G_fatal_error("WTF");
  456. }
  457. else if (new_isle < 0) {
  458. Vect_list_append(IList, -new_isle);
  459. }
  460. }
  461. if (Map->plus.Line[abs(line)]->left == 0 || Map->plus.Line[abs(line)]->right == 0)
  462. G_fatal_error("dissolve with neighbour area n bounds: corrupt topology");
  463. }
  464. }
  465. /* dissolve with outer isle */
  466. else if (dissolve_neighbour < 0) {
  467. int nisles_old;
  468. G_debug(3, "dissolve with outer isle");
  469. if (dissolve_neighbour != outer_isle)
  470. G_fatal_error("wrong outer isle to dissolve");
  471. /* get isle boundaries */
  472. Vect_get_isle_boundaries(Map, -dissolve_neighbour, NList);
  473. /* delete area from topo */
  474. dig_del_area(&(Map->plus), area);
  475. /* delete isle from topo */
  476. dig_del_isle(&(Map->plus), -dissolve_neighbour);
  477. /* delete boundaries from topo */
  478. for (i = 0; i < AList->n_values; i++) {
  479. line = AList->value[i];
  480. dig_del_line(&(Map->plus), line);
  481. }
  482. /* rebuild isles from leftover boundaries */
  483. for (i = 0; i < BList->n_values; i++) {
  484. line = BList->value[i];
  485. if (Map->plus.Line[abs(line)]->left == 0 || Map->plus.Line[abs(line)]->right == 0) {
  486. int new_isle;
  487. nisles_old = Vect_get_num_islands(Map);
  488. new_isle = Vect_build_line_area(Map, abs(line), (line > 0 ? GV_RIGHT : GV_LEFT));
  489. if (new_isle > 0 || (new_isle < 0 && nisles_old == Vect_get_num_islands(Map)))
  490. G_fatal_error("failed to build new isle");
  491. if (new_isle < 0) {
  492. Vect_list_append(IList, -new_isle);
  493. }
  494. }
  495. /* check */
  496. if (Map->plus.Line[abs(line)]->left == 0 || Map->plus.Line[abs(line)]->right == 0)
  497. G_fatal_error("dissolve with outer isle: corrupt topology");
  498. }
  499. for (i = 0; i < NList->n_values; i++) {
  500. line = NList->value[i];
  501. if (!Vect_line_alive(Map, abs(line)))
  502. continue;
  503. if (Map->plus.Line[abs(line)]->left == 0 || Map->plus.Line[abs(line)]->right == 0) {
  504. int new_isle;
  505. new_isle = Vect_build_line_area(Map, abs(line), (line > 0 ? GV_RIGHT : GV_LEFT));
  506. if (new_isle >= 0)
  507. G_fatal_error("WTF");
  508. else if (new_isle < 0) {
  509. Vect_list_append(IList, -new_isle);
  510. }
  511. }
  512. /* check */
  513. if (Map->plus.Line[abs(line)]->left == 0 || Map->plus.Line[abs(line)]->right == 0)
  514. G_fatal_error("dissolve with outer isle n bounds: corrupt topology");
  515. }
  516. }
  517. /* attach all isles to outer or new area */
  518. if (outer_area >= 0) {
  519. for (i = 0; i < IList->n_values; i++) {
  520. Map->plus.Isle[IList->value[i]]->area = outer_area;
  521. if (outer_area > 0)
  522. dig_area_add_isle(&(Map->plus), outer_area, IList->value[i]);
  523. }
  524. }
  525. nremoved++;
  526. }
  527. if (removed_area)
  528. *removed_area = size_removed;
  529. G_verbose_message(_("%d areas of total size %g removed"), nremoved,
  530. size_removed);
  531. Vect_build_partial(Map, GV_BUILD_BASE);
  532. Vect_merge_lines(Map, GV_BOUNDARY, NULL, NULL);
  533. return (nremoved);
  534. }