remove_areas.c 16 KB

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