123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615 |
- /*!
- \file lib/vector/Vlib/remove_areas.c
- \brief Vector library - clean geometry (remove small areas)
- Higher level functions for reading/writing/manipulating vectors.
- (C) 2001-2009 by the GRASS Development Team
- This program is free software under the GNU General Public License
- (>=v2). Read the file COPYING that comes with GRASS for details.
- \author Radim Blazek, Markus Metz
- */
- #include <stdlib.h>
- #include <grass/vector.h>
- #include <grass/glocale.h>
- int Vect_remove_small_areas_nat(struct Map_info *, double,
- struct Map_info *, double *);
- int Vect_remove_small_areas_ext(struct Map_info *, double,
- struct Map_info *, double *);
- /*!
- \brief Remove small areas from the map map.
- Centroid of the area and the longest boundary with adjacent area is
- removed. Map topology must be built GV_BUILD_CENTROIDS.
- \param[in,out] Map vector map
- \param thresh maximum area size for removed areas
- \param[out] Err vector map where removed lines and centroids are written
- \param removed_area pointer to where total size of removed area is stored or NULL
- \return number of removed areas
- */
- int
- Vect_remove_small_areas(struct Map_info *Map, double thresh,
- struct Map_info *Err, double *removed_area)
- {
- if (Map->format == GV_FORMAT_NATIVE)
- return Vect_remove_small_areas_nat(Map, thresh, Err, removed_area);
- else
- return Vect_remove_small_areas_ext(Map, thresh, Err, removed_area);
- }
- int
- Vect_remove_small_areas_ext(struct Map_info *Map, double thresh,
- struct Map_info *Err, double *removed_area)
- {
- int area, nareas;
- int nremoved = 0;
- struct ilist *List;
- struct ilist *AList;
- struct line_pnts *Points;
- struct line_cats *Cats;
- double size_removed = 0.0;
- List = Vect_new_list();
- AList = Vect_new_list();
- Points = Vect_new_line_struct();
- Cats = Vect_new_cats_struct();
- nareas = Vect_get_num_areas(Map);
- for (area = 1; area <= nareas; area++) {
- int i, j, centroid, dissolve_neighbour;
- double length, size;
- G_percent(area, nareas, 1);
- G_debug(3, "area = %d", area);
- if (!Vect_area_alive(Map, area))
- continue;
- size = Vect_get_area_area(Map, area);
- if (size > thresh)
- continue;
- size_removed += size;
- /* The area is smaller than the limit -> remove */
- /* Remove centroid */
- centroid = Vect_get_area_centroid(Map, area);
- if (centroid > 0) {
- if (Err) {
- Vect_read_line(Map, Points, Cats, centroid);
- Vect_write_line(Err, GV_CENTROID, Points, Cats);
- }
- Vect_delete_line(Map, centroid);
- }
- /* Find the adjacent area with which the longest boundary is shared */
- Vect_get_area_boundaries(Map, area, List);
- /* Create a list of neighbour areas */
- Vect_reset_list(AList);
- for (i = 0; i < List->n_values; i++) {
- int line, left, right, neighbour;
- line = List->value[i];
- if (!Vect_line_alive(Map, abs(line))) /* Should not happen */
- G_fatal_error(_("Area is composed of dead boundary"));
- Vect_get_line_areas(Map, abs(line), &left, &right);
- if (line > 0)
- neighbour = left;
- else
- neighbour = right;
- G_debug(4, " line = %d left = %d right = %d neighbour = %d",
- line, left, right, neighbour);
- Vect_list_append(AList, neighbour); /* this checks for duplicity */
- }
- G_debug(3, "num neighbours = %d", AList->n_values);
- /* Go through the list of neighbours and find that with the longest boundary */
- dissolve_neighbour = 0;
- length = -1.0;
- for (i = 0; i < AList->n_values; i++) {
- int neighbour1;
- double l = 0.0;
- neighbour1 = AList->value[i];
- G_debug(4, " neighbour1 = %d", neighbour1);
- for (j = 0; j < List->n_values; j++) {
- int line, left, right, neighbour2;
- line = List->value[j];
- Vect_get_line_areas(Map, abs(line), &left, &right);
- if (line > 0)
- neighbour2 = left;
- else
- neighbour2 = right;
- if (neighbour2 == neighbour1) {
- Vect_read_line(Map, Points, NULL, abs(line));
- l += Vect_line_length(Points);
- }
- }
- if (l > length) {
- length = l;
- dissolve_neighbour = neighbour1;
- }
- }
- G_debug(3, "dissolve_neighbour = %d", dissolve_neighbour);
- /* Make list of boundaries to be removed */
- Vect_reset_list(AList);
- for (i = 0; i < List->n_values; i++) {
- int line, left, right, neighbour;
- line = List->value[i];
- Vect_get_line_areas(Map, abs(line), &left, &right);
- if (line > 0)
- neighbour = left;
- else
- neighbour = right;
- G_debug(3, " neighbour = %d", neighbour);
- if (neighbour == dissolve_neighbour) {
- Vect_list_append(AList, abs(line));
- }
- }
- /* Remove boundaries */
- for (i = 0; i < AList->n_values; i++) {
- int line;
- line = AList->value[i];
- if (Err) {
- Vect_read_line(Map, Points, Cats, line);
- Vect_write_line(Err, GV_BOUNDARY, Points, Cats);
- }
- Vect_delete_line(Map, line);
- }
- nremoved++;
- nareas = Vect_get_num_areas(Map);
- }
- if (removed_area)
- *removed_area = size_removed;
- G_message(_("%d areas of total size %g removed"), nremoved,
- size_removed);
- return (nremoved);
- }
- /* much faster version */
- int
- Vect_remove_small_areas_nat(struct Map_info *Map, double thresh,
- struct Map_info *Err, double *removed_area)
- {
- int area, nareas;
- int nremoved = 0;
- struct ilist *List;
- struct ilist *AList;
- struct ilist *BList;
- struct ilist *NList;
- struct ilist *IList;
- struct line_pnts *Points;
- struct line_cats *Cats;
- double size_removed = 0.0;
- int dissolve_neighbour;
- int line, left, right, neighbour;
- int nisles, nnisles;
- List = Vect_new_list();
- AList = Vect_new_list();
- BList = Vect_new_list();
- NList = Vect_new_list();
- IList = Vect_new_list();
- Points = Vect_new_line_struct();
- Cats = Vect_new_cats_struct();
- nareas = Vect_get_num_areas(Map);
- for (area = 1; area <= nareas; area++) {
- int i, j, centroid, ncentroid;
- double length, l, size;
- int outer_area = -1;
- int narea, same_atype = 0;
- G_percent(area, nareas, 1);
- G_debug(3, "area = %d", area);
- if (!Vect_area_alive(Map, area))
- continue;
- size = Vect_get_area_area(Map, area);
- if (size > thresh)
- continue;
- size_removed += size;
- /* The area is smaller than the limit -> remove */
- /* Remove centroid */
- centroid = Vect_get_area_centroid(Map, area);
- if (centroid > 0) {
- if (Err) {
- Vect_read_line(Map, Points, Cats, centroid);
- Vect_write_line(Err, GV_CENTROID, Points, Cats);
- }
- Vect_delete_line(Map, centroid);
- }
- /* Find the adjacent area with which the longest boundary is shared */
- Vect_get_area_boundaries(Map, area, List);
- /* Create a list of neighbour areas */
- Vect_reset_list(AList);
- for (i = 0; i < List->n_values; i++) {
- line = List->value[i];
- if (!Vect_line_alive(Map, abs(line))) /* Should not happen */
- G_fatal_error(_("Area is composed of dead boundary"));
- Vect_get_line_areas(Map, abs(line), &left, &right);
- if (line > 0)
- neighbour = left;
- else
- neighbour = right;
- G_debug(4, " line = %d left = %d right = %d neighbour = %d",
- line, left, right, neighbour);
- ncentroid = 0;
- if (neighbour > 0) {
- ncentroid = Vect_get_area_centroid(Map, neighbour);
- }
- if (neighbour < 0) {
- narea = Vect_get_isle_area(Map, -neighbour);
- if (narea > 0)
- ncentroid = Vect_get_area_centroid(Map, narea);
- }
- if ((centroid != 0) + (ncentroid != 0) != 1)
- same_atype = 1;
- Vect_list_append(AList, neighbour); /* this checks for duplicity */
- }
- G_debug(3, "num neighbours = %d", AList->n_values);
- if (AList->n_values == 1)
- same_atype = 0;
- /* Go through the list of neighbours and find the one with the longest boundary */
- dissolve_neighbour = 0;
- length = -1.0;
- for (i = 0; i < AList->n_values; i++) {
- int neighbour1;
- l = 0.0;
- neighbour1 = AList->value[i];
- G_debug(4, " neighbour1 = %d", neighbour1);
-
- if (same_atype) {
- ncentroid = 0;
- if (neighbour1 > 0) {
- ncentroid = Vect_get_area_centroid(Map, neighbour1);
- }
- if (neighbour1 < 0) {
- narea = Vect_get_isle_area(Map, -neighbour1);
- if (narea > 0)
- ncentroid = Vect_get_area_centroid(Map, narea);
- }
- if ((centroid != 0) + (ncentroid != 0) == 1)
- continue;
- }
- for (j = 0; j < List->n_values; j++) {
- int neighbour2;
- line = List->value[j];
- Vect_get_line_areas(Map, abs(line), &left, &right);
- if (line > 0)
- neighbour2 = left;
- else
- neighbour2 = right;
- if (neighbour2 == neighbour1) {
- Vect_read_line(Map, Points, NULL, abs(line));
- l += Vect_line_length(Points);
- }
- }
- if (l > length) {
- length = l;
- dissolve_neighbour = neighbour1;
- }
- }
- G_debug(3, "dissolve_neighbour = %d", dissolve_neighbour);
- if (dissolve_neighbour == 0) {
- G_fatal_error("could not find neighbour to dissolve");
- }
- /* Make list of boundaries to be removed */
- Vect_reset_list(AList);
- Vect_reset_list(BList);
- for (i = 0; i < List->n_values; i++) {
- line = List->value[i];
- Vect_get_line_areas(Map, abs(line), &left, &right);
- if (line > 0)
- neighbour = left;
- else
- neighbour = right;
- G_debug(3, " neighbour = %d", neighbour);
- if (neighbour == dissolve_neighbour) {
- Vect_list_append(AList, abs(line));
- }
- else
- Vect_list_append(BList, line);
- }
- G_debug(3, "remove %d of %d boundaries", AList->n_values, List->n_values);
- /* Get isles inside area */
- Vect_reset_list(IList);
- if ((nisles = Vect_get_area_num_isles(Map, area)) > 0) {
- for (i = 0; i < nisles; i++) {
- Vect_list_append(IList, Vect_get_area_isle(Map, area, i));
- }
- }
- /* Remove boundaries */
- for (i = 0; i < AList->n_values; i++) {
- int ret;
- line = AList->value[i];
- if (Err) {
- Vect_read_line(Map, Points, Cats, line);
- Vect_write_line(Err, GV_BOUNDARY, Points, Cats);
- }
- /* Vect_delete_line(Map, line); */
- /* delete the line from coor */
- ret = V1_delete_line_nat(Map, Map->plus.Line[line]->offset);
- if (ret == -1) {
- G_fatal_error(_("Could not delete line from coor"));
- }
- }
- /* update topo */
- if (dissolve_neighbour > 0) {
- G_debug(3, "dissolve with neighbour area");
- /* get neighbour centroid */
- centroid = Vect_get_area_centroid(Map, dissolve_neighbour);
- /* get neighbour isles */
- if ((nnisles = Vect_get_area_num_isles(Map, dissolve_neighbour)) > 0) {
- for (i = 0; i < nnisles; i++) {
- Vect_list_append(IList, Vect_get_area_isle(Map, dissolve_neighbour, i));
- }
- }
- /* get neighbour boundaries */
- Vect_get_area_boundaries(Map, dissolve_neighbour, NList);
- /* delete area from topo */
- dig_del_area(&(Map->plus), area);
- /* delete neighbour area from topo */
- dig_del_area(&(Map->plus), dissolve_neighbour);
- /* delete boundaries from topo */
- for (i = 0; i < AList->n_values; i++) {
- struct P_topo_b *topo;
- struct P_node *Node;
- line = AList->value[i];
- topo = (struct P_topo_b *)Map->plus.Line[line]->topo;
- Node = Map->plus.Node[topo->N1];
- dig_del_line(&(Map->plus), line, Node->x, Node->y, Node->z);
- }
- /* build new area from leftover boundaries of deleted area */
- for (i = 0; i < BList->n_values; i++) {
- struct P_topo_b *topo;
- int new_isle;
- line = BList->value[i];
- topo = Map->plus.Line[abs(line)]->topo;
- if (topo->left == 0 || topo->right == 0) {
- new_isle = Vect_build_line_area(Map, abs(line), (line > 0 ? GV_RIGHT : GV_LEFT));
- if (new_isle > 0) {
- if (outer_area > 0)
- G_fatal_error("dissolve_neighbour > 0, new area has already been created");
- outer_area = new_isle;
- /* reattach centroid */
- Map->plus.Area[outer_area]->centroid = centroid;
- if (centroid > 0) {
- struct P_topo_c *ctopo = Map->plus.Line[centroid]->topo;
- ctopo->area = outer_area;
- }
- }
- else if (new_isle < 0) {
- /* leftover boundary creates a new isle */
- Vect_list_append(IList, -new_isle);
- }
- else {
- /* neither area nor isle, should not happen */
- G_fatal_error(_("dissolve_neighbour > 0, failed to build new area"));
- }
- }
- /* check */
- if (topo->left == 0 || topo->right == 0)
- G_fatal_error(_("Dissolve with neighbour area: corrupt topology"));
- }
- /* build new area from neighbour's boundaries */
- for (i = 0; i < NList->n_values; i++) {
- struct P_topo_b *topo;
- line = NList->value[i];
- if (!Vect_line_alive(Map, abs(line)))
- continue;
- topo = Map->plus.Line[abs(line)]->topo;
- if (topo->left == 0 || topo->right == 0) {
- int new_isle;
- new_isle = Vect_build_line_area(Map, abs(line), (line > 0 ? GV_RIGHT : GV_LEFT));
- if (new_isle > 0) {
- if (outer_area > 0)
- G_fatal_error("dissolve_neighbour > 0, new area has already been created");
- outer_area = new_isle;
- /* reattach centroid */
- Map->plus.Area[outer_area]->centroid = centroid;
- if (centroid > 0) {
- struct P_topo_c *ctopo = Map->plus.Line[centroid]->topo;
- ctopo->area = outer_area;
- }
- }
- else if (new_isle < 0) {
- /* Neigbour's boundary creates a new isle */
- Vect_list_append(IList, -new_isle);
- }
- else {
- /* neither area nor isle, should not happen */
- G_fatal_error(_("Failed to build new area"));
- }
- }
- if (topo->left == 0 || topo->right == 0)
- G_fatal_error(_("Dissolve with neighbour area: corrupt topology"));
- }
- }
- /* dissolve with outer isle */
- else if (dissolve_neighbour < 0) {
- G_debug(3, "dissolve with outer isle");
- outer_area = Vect_get_isle_area(Map, -dissolve_neighbour);
- /* get isle boundaries */
- Vect_get_isle_boundaries(Map, -dissolve_neighbour, NList);
- /* delete area from topo */
- dig_del_area(&(Map->plus), area);
- /* delete isle from topo */
- dig_del_isle(&(Map->plus), -dissolve_neighbour);
- /* delete boundaries from topo */
- for (i = 0; i < AList->n_values; i++) {
- struct P_topo_b *topo;
- struct P_node *Node;
- line = AList->value[i];
- topo = (struct P_topo_b *)Map->plus.Line[line]->topo;
- Node = Map->plus.Node[topo->N1];
- dig_del_line(&(Map->plus), line, Node->x, Node->y, Node->z);
- }
- /* build new isle(s) from leftover boundaries */
- for (i = 0; i < BList->n_values; i++) {
- struct P_topo_b *topo;
- line = BList->value[i];
- topo = Map->plus.Line[abs(line)]->topo;
- if (topo->left == 0 || topo->right == 0) {
- int new_isle;
- new_isle = Vect_build_line_area(Map, abs(line), (line > 0 ? GV_RIGHT : GV_LEFT));
- if (new_isle < 0) {
- Vect_list_append(IList, -new_isle);
- }
- else {
- /* area or nothing should not happen */
- G_fatal_error(_("Failed to build new isle"));
- }
- }
- /* check */
- if (topo->left == 0 || topo->right == 0)
- G_fatal_error(_("Dissolve with outer isle: corrupt topology"));
- }
- /* build new isle(s) from old isle's boundaries */
- for (i = 0; i < NList->n_values; i++) {
- struct P_topo_b *topo;
- line = NList->value[i];
- if (!Vect_line_alive(Map, abs(line)))
- continue;
- topo = Map->plus.Line[abs(line)]->topo;
- if (topo->left == 0 || topo->right == 0) {
- int new_isle;
- new_isle = Vect_build_line_area(Map, abs(line), (line > 0 ? GV_RIGHT : GV_LEFT));
- if (new_isle < 0) {
- Vect_list_append(IList, -new_isle);
- }
- else {
- /* area or nothing should not happen */
- G_fatal_error(_("Failed to build new isle"));
- }
- }
- /* check */
- if (topo->left == 0 || topo->right == 0)
- G_fatal_error(_("Dissolve with outer isle: corrupt topology"));
- }
- }
- if (dissolve_neighbour > 0 && outer_area <= 0) {
- G_fatal_error(_("Area merging failed"));
- }
- /* attach all isles to outer or new area */
- if (outer_area >= 0) {
- for (i = 0; i < IList->n_values; i++) {
- if (!Map->plus.Isle[IList->value[i]])
- continue;
- Map->plus.Isle[IList->value[i]]->area = outer_area;
- if (outer_area > 0)
- dig_area_add_isle(&(Map->plus), outer_area, IList->value[i]);
- }
- }
- nremoved++;
- nareas = Vect_get_num_areas(Map);
- }
- if (removed_area)
- *removed_area = size_removed;
- G_message(_("%d areas of total size %g removed"), nremoved,
- size_removed);
- Vect_destroy_list(List);
- Vect_destroy_list(AList);
- Vect_destroy_list(BList);
- Vect_destroy_list(NList);
- Vect_destroy_list(IList);
- Vect_destroy_line_struct(Points);
- Vect_destroy_cats_struct(Cats);
- return (nremoved);
- }
|