remove_areas.c 16 KB

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